From b0cb38cf07bfbe719a86add85982aa53d1fb2b5d Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Mon, 31 Jan 2022 15:14:58 +0100 Subject: [PATCH 001/218] [Gradle Release Plugin] - new version commit: '2.0-M5-SNAPSHOT'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3e28826e05..29e7944834 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ #Tue, 07 Apr 2015 22:45:24 +0200 group=alfio -version=2.0-M4 +version=2.0-M5-SNAPSHOT sourceCompatibility=11 targetCompatibility=11 From 19be24b8441dedfad80c28c99c2dc6d7ad2d7f51 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Mon, 31 Jan 2022 18:08:50 +0100 Subject: [PATCH 002/218] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0ecd788e8..0d7717491d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The open source ticket reservation system. ## Warning As the work for Alf.io [v2](https://github.com/alfio-event/alf.io/milestones) has started, this branch may contain **unstable** and **untested** code. -If you want to build and deploy alf.io by yourself, we strongly suggest you to use the [2.0-M3-maintenance](https://github.com/alfio-event/alf.io/tree/2.0-M3-maintenance) branch, as it contains production-ready code. +If you want to build and deploy alf.io by yourself, we strongly suggest you to use the [2.0-M4-maintenance](https://github.com/alfio-event/alf.io/tree/2.0-M4-maintenance) branch, as it contains production-ready code. ## Prerequisites From e5e26fc606428e343b33884a4025b1fce3648c93 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Mon, 31 Jan 2022 18:39:02 +0100 Subject: [PATCH 003/218] update gradle and dependencies --- build.gradle | 34 ++++++++++------------- gradle/wrapper/gradle-wrapper.jar | Bin 58695 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 ++ gradlew.bat | 25 +++++------------ 5 files changed, 25 insertions(+), 38 deletions(-) diff --git a/build.gradle b/build.gradle index 3f8d227ba7..9249300a21 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,6 @@ import java.time.format.DateTimeFormatter buildscript { dependencies { - classpath 'com.opentable.components:otj-pg-embedded:0.13.3' classpath 'org.postgresql:postgresql:42.2.20' //this is for processing the index.html at compile time classpath "com.github.alfio-event:alf.io-public-frontend:$alfioPublicFrontendVersion" @@ -33,17 +32,17 @@ buildscript { } plugins { - id 'io.freefair.lombok' version '5.3.3.3' + id 'io.freefair.lombok' version '6.3.0' id 'java' id 'idea' - id 'org.kordamp.gradle.jacoco' version '0.45.0' - id 'com.github.ben-manes.versions' version '0.38.0' + id 'org.kordamp.gradle.jacoco' version '0.47.0' + id 'com.github.ben-manes.versions' version '0.41.0' id 'com.github.hierynomus.license' version '0.16.1' id 'net.researchgate.release' version '2.8.1' - id 'org.springframework.boot' version '2.4.5' + id 'org.springframework.boot' version '2.6.3' id 'org.sonarqube' version '3.3' - id 'net.ltgt.errorprone' version '2.0.1' - id 'com.github.node-gradle.node' version '3.1.0' + id 'net.ltgt.errorprone' version '2.0.2' + id 'com.github.node-gradle.node' version '3.1.1' } apply plugin: 'java' @@ -107,7 +106,7 @@ repositories { dependencies { implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" - implementation 'com.auth0:java-jwt:3.18.2' + implementation 'com.auth0:java-jwt:3.18.3' implementation "com.fasterxml.jackson.core:jackson-core" implementation "com.fasterxml.jackson.core:jackson-databind" implementation "org.springframework.boot:spring-boot-properties-migrator", { @@ -136,7 +135,7 @@ dependencies { implementation "org.apache.logging.log4j:log4j-slf4j-impl:2.17.1" /**/ - implementation "com.stripe:stripe-java:20.50.0" + implementation 'com.stripe:stripe-java:20.97.0' implementation 'com.paypal.sdk:checkout-sdk:1.0.5' implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.1', { @@ -162,9 +161,9 @@ dependencies { compileOnly "javax.servlet:javax.servlet-api:4.0.1" testImplementation "javax.servlet:javax.servlet-api:4.0.1" - testImplementation 'org.testcontainers:testcontainers:1.16.2' - testImplementation 'org.testcontainers:postgresql:1.16.2' - testImplementation 'org.testcontainers:junit-jupiter:1.16.2' + testImplementation 'org.testcontainers:testcontainers:1.16.3' + testImplementation 'org.testcontainers:postgresql:1.16.3' + testImplementation 'org.testcontainers:junit-jupiter:1.16.3' testImplementation "org.springframework.boot:spring-boot-starter-test", { exclude module : 'spring-boot-starter-logging' } @@ -327,6 +326,9 @@ test { } } +springBoot { + mainClass = 'alfio.config.SpringBootLauncher' +} bootRun { def externalConfig = new File("./custom.jvmargs") @@ -344,13 +346,10 @@ bootRun { opts += externalConfig.readLines() } jvmArgs = opts - mainClass = 'alfio.config.SpringBootLauncher' } bootWar { - mainClassName = 'alfio.config.SpringBootLauncher' - classifier = 'boot' - + archiveClassifier.set('boot') def bowerDir = "resources/bower_components" def excludesFile = new File("./lib_exclude") if(excludesFile.exists()) { @@ -409,9 +408,6 @@ release { signTag = true } } -// see https://github.com/freefair/gradle-plugins/issues/31#issuecomment-475355674 -// since we have a custom lombok.config configuration file, we disable automatic override -generateLombokConfig.enabled = false // MJML email templates translations to HTML node { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c2faf2fc91d853cd5d4242b5547257070..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 12842 zcmY+q1ymhDmoSOmQr324hm`&0SZbS3R18r37J8Z0F-T>@gIK` zatajf2b1lO#&E_RnGDF51uk%8Wcxm3`%Yhe7Psx?*?eZ?8M9_+G(?L=s^OG1n#S(NP3gF?2Mr2^f5E7sM~iVC`Rn;(-^MZ zZu*ZXB;XmgvPls(e#)MMTObsEx9oNz-K?AmQ8pP&P7vqx*=5zxjU+ye_1R<%KSg1? z7H&Yh))(Ke!Pa+aVuWxPKa_~Qo_IH}*;tV8n~O*Xa?t3P^9=L%=wOL1=~{LVv}mU8Q#e6s>v}iV8cDP|EdY)`dp≶7^21 ziF~qst3+S0y_IcTmzBD?t^AL=8|hpx>4aXc#L1YriEI=T#&IZ=SoAEyLg|^3d~uWZ zL(@1$!3on^gfz^e5VdZe5qx_>I%?g|J-FS>NG7S8Uwqt9t6KDa`8Nu!bDng+bM`&i zd>s2#sQ2Dsh6c}3YYi}8DqsK)DG!%;@xqz(<#=W`C`X+!HhtF~r~9OsI`@n36>D}N zz^HjPst0d<*2#=afSFiYwBeNZDk>BahnaW;GkQDA235(RJ%j;vVg80O#gk|q<#+OO z!F(BArIYDQG-{DlHpf+F=!)yw08zWccjd6DKgR+zJ(0X3zS;mzg+Na{$2N+AhF7`& zXj`aBWy{YG#8s$C5=GZH$a@!+F42?=O~WoaIjO;k;0P0nE5|ma;I^@xN`kKvIjTQe z1!_si%O1V@BP`r(WwTpr7HN&p#_-)5!T z%!r5ZL79g`v%i29=J2rPglr;%LCc+ZSZeh71?CfOgZ&EJdacV35*58xwhWGhyMhx{ z5KAVHq&&zae)(vc?T~KB9rtcfzy#SAUvce5`+$`_U7}=j*;@5(PyBoTp#IwDtV?s% zQ%T#rekISAFx`AeHyBx6BP^4OtUo>VhbksSk&W=OkQIO#SJ13R8z6r|HNM}$TK=58 z^$>Cg`+P;E@||v&RXQ8dF?fqSS3;wKND5tF(tf3C`q!LEI9_~9LgscI=n#Q>Vl6%6 z^xQ<;f6C*>yStD8WZ4LPzJjmeuu1L`A4BDvEy6DgDMC)PB+3}KWft<^5DPgko{>P8 zJL=zIrDlQ3l54nAxi=;0*HF+cQ`|0Z;~#mt0NHndDI8Ft6^Gp+Lz!19<=L3-abvfX zelFvqpMs+)n2}tXR2j_UG99=i2A)GzpZxTtF=_i+PyVcT4m=oLbh0j3wb~T*1D(f! zOnvTcyI^VbldY>z*{sBnk&j3`-I6GqvB;Qa*bl<5YKpLMNKjDk-$VW9y)f6Qa?T73 z1=aTsLXIW~Xm4p^spI@Hmcn0=j#SgUrQ(LwQu{s6rO7cNL8G>CZWT(hIbdv%x(Jlp zoI&SgpA?j``5vR&m!53m5=zO&hWkznAAO#F&1pI^L3;~$fir#2Cha{-SD4F2dZ$Yj zNWSt;3dLNmPZ<;D0kQqC&yn>qqCMISL58?}bV(f=u%P^DVHARl?p=uptqCK6qHR%G znz@gHYqEnCEL=>78`c?7$>81*%RQ`@urhDyDti}_ZIXnVa)~U{)lq9bj?aBpb1|OX zQEOY8nV`I7nqbYP%pqaNpQZht6Jst`i`{B$ycuhg>p)3{T|=C)ZRx zwhOaI{+g~G@s-nQB66k4ZKP7Wk4v)bVT$sdEEvJj5EkX)2#Rp1J(m+pLGRGtgR}!C zJ1^uNmx6bMEDWh)dOtRzDkdg7lNs7AO6;LFpmezCp}|2dbseLD5M?D7VP+y`GysD~ zXb)?J3jG=5(Rn1_;i`Dqld zLN8F94c4{|1+YfvKa)vn+;*{ju_%uj`H`ke;KQ2P7DD5nGOQP(R8l=AL0{o9qc%9& z4e))*rFyxhsM%wgJC6S4tJLteds>&34_6tvv7a(#F`kk%031W1Aq<#&3|2ZN-Cqq`-l5Ajt zmAD72)g^6kQ@$3=wef)3tC4m)dsw?AxwR=`#N_`9Hd+t$4SzJ+Za8)malG?}{YbGV zxcLZ87Enlr@O~eE@6qx44m*uKyFE-L%FP1HxR_($c}_VqmXk%xb*nPsReTfvRCy#; zLY#`)G1RGkp=-|NJ^jIMW}3=(vjF6sXq}{QLw%AcwOIS4Xzu*SI~An6k)^=@T}{+b z;{p5VP*8g0P*4>A`R0;9;+Nh5H3o>@M5CSo@o)`_E?{vin&S{F5*+l|B+sN&hr~i^ zxo)Y1WCr~t-M*v{c=O$137j0hxQnsK3wkdHI@jz{r>wsxUt;$AWa$ls__3NTo)gRm zxs5xy_-19*m7b*fKPY(QViL^@bJ0u|)*rDFGM{5vt|In|Dbn>J8Y}9zMGS2hhAyEyX;#g( z3$svdx$kb`47#gDE}`MAb8TA7R|g7nS`|htx!e*OH3KH;-=d|O^tcqIH0d%+3iWA0 zc>|NUCIvSN=od!@4k5Y~-RqKc;Mj?P6lV=^P5w4Y*^K}?DsbbI!s~r})~$Z%6UvLI z5j+vg$jfj?7@8$a{2edF8S?`VQ@8Z4q4sv=4Npp2Rk!3}&cKMVgm2Y^BjZl#jZ?}) zxnI}B=kjh{W(VDN$z6XX19np0>bUe=C6Ih6_wN`?Vce#N4D9Rl3fX67_r(uM_$4H;FS0L^8S4SsUjic=MUP==s$OM)&NEvp)gDY#mLjhipsjL4`P4~y+`Ffxn){Z zM1N=8c5d!;9JDPTH^%wTa}r{{C6e<~q%Z-FCbp1aBH&ZH-)oNV1Fn^++vwDsdP6*} zaVhuu2m6!6^tlgaCy^m$Egs|YdX=V|Me#&Rq<3K`OoZI~O5Bm)H(OTPBblGUmJg0| z-izCVizZ(K;ct6*^BV0U#+S@wOf5Zixt#8bM^uTH0|NxC-~Y)n6Xq#4ROj%DVD)8= zBCj(Tvjoy@S#8(io3h46W>%(0?BH3|f~ zZq)Djpdf3=53UQ^^XbRF&r^wwiCCoP-$on0UIe_qQp8l(D;vgp5?-tOGOH$Gjwd~0 zP-c9qN8_Z?BDcLlJvT^o_QFSEa0&@kuTLnrD_uKDAQZ7!g`IO9R9fTT@7Imu&@^@m z?qLv2Y{YygNjB;sk7J*DU>$t@B2QBhPY|r*5cj8Z9cR1l3OW>>kyz_7VIbUnO1*T+ z9R_H!tG(65#gKrw8j9+gx+_FfNZzggvg8ut<>bLdeet7<#JLJ_x1f%XFklxkhk;Q& zlehT2JngNwJRkN<$!~!2&0Ypouxad+=bQtZ!X$UphLDQG_S5)O&__;c_f*|+lp2ZZ zb76mUyr3?H+16hMIi0xCNVPOzqbJg&7(w8MVCzHGtbS&j1f^eEw%Ax_x;-@du9i|; zY=1W0GG4sSZfnWW9v0COT!>0Kp4UDL2Hj+kovXh(BB?mhhdoSJ4=u}gXno7mDu=dC zoEbrTZk!pao1a3}xpEUS8VADYb;P9bB4H%rWa4Mx=Y$I85KhEnNeh!@&^4nf9H9Xm z!v|Iya%#6W8M4A#kbg|B7~F`1Ag0{=1FS6FcG-QC&M0#{?C~|i(mn~Fqr7Sf?Yse5 zuAfH&M+NU zr;=Ulc0TW}u9-^{O7RHY6OPIhyaTZE=(Nl&!jj2uVS5!ZQY2LBqP6e)7&F3Q_Hab_ zLrV(2QNJR@Q3@ySlY`qAJ9RW~ANP~kCZVc+(E_?xFf#1GdC0(ny@RWUMHZ%x#$)ve zcJ}OJcEnWXXK3lgvCS6;RcVVxAN!_E@w<4vAMGFa<$G1RE+wyj%X;u}&YuEpoFBLY zM0*$}OUKT3lDDD0O&TM_#1oBU&8>dbIXCK0$D*1#`;Df(2uT^Ys9whszl=P|xI zK4W*LaJ@*-8JDeOOjy3z`Q?(C2>>3>fNK3wAi&Px<>6wQKf}hc^znUVz-_hJ(=Wd4 z9IgSrq}Qf)hGfeb7E!z>^fAEWN>&Y|bLXLO1^4350UN=XN>k)gBATK}fRry2DzFf> zeI(W{Xb~dAwxAs=Iz=}3s2+eqikF2ZX30Fu3T?1I`cx!0rN1g2`c0fKmhEaZJ7nf# z7i(J~BWxF}HSK0xuHTjRBVugcLHr;P4EsClv;7N>sBvGKacB8^N>1Pj{+H4BO>brw z0Z=^L{Yk5nDlH1J>{YeU!Y6DDQyZmEqf3LCmI8@+&eAWLcdAks4e)z-%Fp|y7pkRL zh}ia&0kgEwac`26TUTAYnw`*P9-Q7OWaElwe(&9MbY7Am?<9OE zFl?kb79&+DH2+NM@b%G?f-GhaeE#IQrH%0x#4(vYW~7*gBkYlZ_UG$X<**g4C=s1F zetpyc6kF;#-gZ{o zo5%FNck~|JmFqChIa4HyzJ;9s^E2Q(q|ExN5GJ_+N&t=PR~t6#B$4n*`iuX z1ar~vtGu~kDGyTq9B@908w}v9v2?bp-!9ig&naSfi|YE`Z$sk-lBk*YOlN|43gU^lO_#1eF&9897yLT7 zYcHsfu2`qSC6AbNB}O{3wPcAu%$O;&a4co+Tp2_=;n%-!MlMGm-@306*aPxS&vEN4 zj(vxTGWQ6asMvUfb*p&*Fs`N}LjI4Z&xgki`R^F0>I4N9QCZ+RXKPC_CuR2&Y^#{2+ z!ilm<k;?lLILj?ya|l9 zOrF)I76r5|z+J+8 ziFg6yfg3{uQbl69k(zf@XXb1Y%n*+s5lv;=~4G5mx-nnZb5v}SQj%*ymKZCt1qOy+hkMR?8 z3gvp`aXHm=DrW6Ny_oLcLxJA%*=Qtx`2sd34-LI3R;| zOyl7p2TBbRhEzz#+0d|LY0{h(3twB_~^+8*w z(MzSza-w44?3^wDf(gH9>2>qWL&SogA z-~dj4T9o)~d0>{1_V$*al&)P&kJE z(;N?J$~(vn9K#c|HbCAO?f$k2SDJQWKaxirtifx|+UMwRCosQtaG|O>CaCtzh+1k_ zUN-Kl6?5rfCS-I>#mU)Ru z`~1=H;0sspAO7fElv->{+Q6+a2p>b zzWKwufce=pd5)@gn41XkS@m8%-2@asCj|(nG2jk~7Sq~Y$}9DXI}3OP5GhER=U&AP z46t6NH}f!7|Jn|2T{;w|BDLC1_ipdm=dMIyzuCbBc>%lXcp#a~kgzS0JDfa0u40m48`rku!q$3Z`?6tz{7*3^*p;uG^uikJU&oxP-l&}0XQc|~h7{Re)JHg*6b%(nxs+$7)^Z;BFV`}*L;>Ih zMs0u!*7d+jPeqM>>`JVZNg&G2h&w?{eiRg}{_C-q$%M!Li&?YZ(2o10ogN!NtSeNC zjIimtk-Li5J5$w6iCygi?yi5%rFx>QPLksnXoCOsKnj zWm@ShV5616Y;`R6(k1=$nob4SvJJy_(#wO@~}HOesm>Yt?QkErQn-m;~p50(~qBvdQO0Tqg#3yus1TtZVpt zez2NfwQCkO9BbTyZKb53b=pgfR5#)@qqG_jn;*jYd8%il*I7t~jol8g3`&N1tZZcU zP?@z6(Ef>6&(i8g=}|}YxuzVGL*SZ}6Xc?$r~90bt*|D*l?gqfI`mopjp%Mhfm?-x z^|Bt(sH}sqdH{8p-4YV~9?TQS?iq*C9y#_-a)8xJ9W+}0A{X$4W6q7yGx!# zioE>n)y?!4H)ge$jK${3)1^DbijD9)Tbm=idENin5;KJ7luQlufA)Y6ykK04aG;=A zS)icEA@z26kQp%oz|5ODGKAd$O^%$&Ocur*fL?wa7`4$$}c9uTHjTP0W!qq|U!ZTXG! zwem4Au0gAe-)dl%%kFQJdq!$^wL1&-O#7CA>qah-HDa=g!Cx@~#P%n-dWGatXH5pk zk`c+UtVD^6d52Jq=ezrLZC@~B>n!Jq_T)DrWX?LLT7^$JoeVtHsWP}AN(G+3&OWvB zI(4}i1CqC`HK;8cZQKq{oi2*sT2YnYWATa7K-%h5+xklmhKb%s_N9oPh`ac0p9$uY z3BUU*z1bEvEi|WFbJ12$SE@|f#%F2^r_OCT8feGbV{pP=MCN*PnKg5M^P+OlOCwFw z?nLdXdPg~8P&5Fp-3Vdn;7aG(I(LjNO-fY!2K-7a*I!t+riEn1v=>-bx$Ua~1Bj+a zAF(54&s&r(8NkRr+XfIwv~g$fxM7+tZw4*5%$~I-pnxQCI@xM9QOeJ=V*gIAP{Dz+)^?Hv zuwfLo(wQwMnKVpXPWE$dD^$WJxp!TtUGHsyrVj0({$@OqbjXyc$x-@JUf#=Uqqbi) zyT#X;Ww$0@Bjh~ATwOgraYm`5Q*M^y+45K`*XB2v+84RTvXBJ&h}vda&w?8Yc8AL~ z{E(zrVR*+rbokD+ihF5}qJC<_c=F%`_~1K77UV3r_yx=XH_jX`KJTEYkJ(jck3EZM zTN~|>DNocbL;@2$a9)Xe{WCc>MTv@bZh0NylBl(x3+y2upl3t7 zQ7zZDZ{h4a^raO-@xk1 z9TpSAw6VztodyVF+}N^t+`@ObqHijM>hLM9<5Cm$oZ4bByuMxEcs3k#se;Ob<;y`{ zqnfp+BI3w$bQh%Zm2*^j#r*Sx0PlHn=rDdx$O^$HD0=yY+DrI*2afM}3sKTZ@{v$O z-))`LxK!);ST-&LCmeR{K^H0?l-DmJlXHfv41D|tq6k}S-gm20i(Z{LNmI^n{J>+P zu zB%Yv;$Pk$%K`K`Vi`gYjjZS2Hnk3~gC}*QCLT;KZ1J--!f>fo73wVt^rrBk9PiE{s z5sNm%+$*S`pjQy9%J73s{&hyJYw8(v9${NeZ#8yu5JwA=ezl1Vbxl9)8ZkwGl362v z*~bq>^-=E|qukP$Mm0G&fvk051!m_ihTqYxyb#9dk=mbPNumYUbkIw!QlCGnl$smp z?Pd0FTDj-HYXak>3#oIM&8n5=wAs#4ma44Our{&10kl=!+tTyQsn+B5IFnLH52(CU zp=XS10t|z;9qb0~&oORiyw67 z*QlVQ@4qfLhFW%QrxT5z)7qI%;-Evg9T}+v->Wv};S)o;a`O4kH-|JI!P6(hWbVZG zu3klVR@UPg!(Xo~05p37>P17&(^+DK)UKQ`b{dp1+2xJ!9=|Yb*WH#q$;66Mks)~W zMmjG)HTiMckF|*bzs=3=`E#6i4GSb{!y+DjpmL|s`+4-nipJ;9kbFZlcL}WZ69mMM z*lyB1-adRRyA^*!a*OvREWFnBd;vdt72M0F!=GewE(`H9SOrwaiKba_ z2auy6$O9LMoP=?7=j@C+8xcc;GTrEwc&#fT#Z95R&vzyOQ7iT?n&nOXTC^koI=)GE z$(dmUqlI4kw;KE+!=tVz(wumguhX!82n+CZIFvnJSc=pG4Q+Hm)3Q${v6l(6TgRPinsg&fK*bQBHc%w@veNmwotb;NZVfgLKZ^#2% zIxyH5z3g|#kQU+yol=TUc44&Ouo4&~*(9|Mth4^Ziw`sodKfG@2tlkZMm|36g9<~Y zWE%=J!`Lbut!g;PM|kaKi#AKUdzP+35Vb)K>IU&~%mgGWmk;j8`q5!&vlSA*M98m8b9sZWplD(I~<0?+~bfN?)r{9JjUZ z9F80S7*a(lDl2}veqYj>63% z>lmBeOXGCiRh7V>Bp`H`v`l32Y2}3|2bcuDO3I%aV4mFBy!A{27_x7Pf07%n(i@eJ zR;Yiy>Te3UH)Hd}mmifLmhNs+H2nEEL;@_Gklm@~{2BQOgQS}Ml7W|PP7>0{&&k{$ zljJ&nLN>xFqFX!R1F;)1Bo1_UO)^yZ;j+GLMdOpbzcZA$gkpckam_KH&fmhifYSzO zXyrf^pR?N8CX{9MZ#qeAdo&4ccDL zQRt^{SOU{mZC}AFVtA~br7&%K74Xd4msMx`!k_TY(=~%unotUH5qP^Q(FPFP zWsL6l4qCNs?i`H^PmD~J^HdiW~& z8oZnipal~XC8Md&EVg)5YTnRVsLCM=1lC=n2CLdH4&Qq9?C;%;h6R4z=I{c9YshCl z-^V%dCZE?>&Oc!z5>c3XI7?70I}oL^kfu`~niM5Q717u8fQ~aR0+=|7Y4rV5i)WIH z##D{*zk(4@F~?nLSX+~$QI6gQ##Oj$#-+Hdval|TN)JY&*Ul_oT;1$iwmYIG5a343 zG39F~7hCJg=Fp^aJa2p@nK=N$fknb=DdHBp#YAiS$jQ*isIX!^gQ0Jpi&qy3%N9}& zizKTkS`I%fZwj;FxNq=0Gk+h3RDT}1QhQES^nt}{i9Kcf^v#X}JQbQ=Jf@tnF_@i+ z+Lft*f;}Hee=F=}=;EV0nWJ5*rct)4iL^MSZFn5Ag5&lp>6lnw@xB1ajN{L6R_qM4 z$pjP>Yo}e@ylmI>4p?1$-S1_~vxAlxv$$z}5|&ZNfedapJEN6Zj3DdFA92{Go#I;( zv?M4UCX=BGZav&L5)K+^iJQswQ_tmu!G;*f`}@{)Id8-lc@8jhrmROub7UL)MsDF@ ziQGSKsu*=wFjsu(zSIMC2piGz?zU_xSc&lxchH?N>8zu=r2Yv=2h-4(@NUorxw`Wr zzq+GpM{ZGOO(e;re{=X5qoJ7y9i^bowl|6+wc^Cgl*zu66P3W8n21l%(QyrVu}YD( z-7{+$7@bq06J75}CoE;~z_U!3ZK@z}zCAIBN#++i!M>BH{6!0VXz;Xff4PDxf%_bK;(#smOVP*Zp*&Gj(tN!!bR0zr6^3C$<+#<{n>3P@zCM zn5(D6FVLC`tmA!4x6lT&)GOh~CgDG}o z-tLW_Bd=~C#zF8Q4vbe*Ky9tB6@TM9u*k9i61T1s^KB;2o8bA{MSX9TfR#z

XiM^r_M1uFTw)(UPqqUJ zed7DJQvOpplYJoNl`A3a2Zr~v)Y}K|*%d7?8;dC*Af}0=(EXrk7hP8PM4v)ZawEv0 z5j5q_6vilv4*ppZ3Wke7%8b`odJu26#YseA?$sP8?@d?TpACTX`G^?%K=Hly9Y$Tj z5`i!}-WH0lQ3yt-&Pf&Z)OxjKfAZ3X`YI2)5o@9EiOA}?kX`^rk;yaOh^Li4VHcT& zd6ztJz^`H!8>cL)a%?Lnofzo0$WPrgkNcP#u@{%~EvA7g#go z+Q4$Q^o_MJTE0G_&9@cgp)WF>2zo>AG}C|(~E^_?ijc2EQ>> zFH1Lxc@i!gDHxvEsrfc+Kiz3Q6Z*NM+U6DH6*-Fv{YDY4>U&eegGH~Xmk~!sd6fw2 z!6^4(MZWhzf(xs6BHy=oS+dir0_JW(j*AIu$9&&p@}T;&6s7(yYidEdkp6pk9}Z(F zk6lG`d!HcJWP{7X)&P5FW;XWU6;zke2e+g*#1kW4L0Auj5pVA45Bhzt{8lj)XyMHu z0p;Q}t*NLnXbGQOTC9WdOQsX;_yLThOP$mzcEbqSBifmDecV;Fqhtm#KxfJTMhY!K zw{1L9za2QtuIWXu0ZYm@Uy72(9^vYajuP$(VAKn+&Jp z!%S;#BqO;02)n~6pFYK8oRC6wXx@kyb?VENM7l?NFg)%^=q4aZ* zwVCZxA8lalF&n`vk#gxD@!9~Aktc+h2UUUax3q2XKQLuL@CpVEpx2IyiH3bALY+Oi zDydtacE1Z|$z5qsCG=%F{}8_ozwieWuM4VcDesuu+wX&YjHm^Ryx)pVtiSLpch7<` zIw9QM%I;(VG9~#Rw2JNt+;?_=O2lA#YSudpgsM`e&(}1 zGdj7U)St4`+Cj#Vn>a;Bj~Q3S1G54;gzq)`b_Hh~ip(`BK#GMkI*RUcK+6ycjl?QN zP%sH5*R$$6A&8j8O4iFJhuHMXLJm|drH+=!_{`60&+tC8*m3Z=YsR@~%eaZyWQI|W zie7;BRL6`LR+4B{%FY~;-^*1GGTCLp!U6VoS36GUAWv$Rcc#|a7DD01{QPB=VyT)? z+1ZV>P=bP1;>v-+j0;BwenO`EKcIbmB3$r*@a~=?5#KB_R$3bTg zOjEutZmWuylIJQEM?28D!4uA#0CZEJHar0TFAW|NwP;WL|EIb_L2>;}e*N!K9E61S zH&u@m!n#CH{C_j}{#ybCRU8z7`Cs{b>@bxSkp3lOm`qAYgB>npnw%V>w}t_+S_Z)s zFhGKq^e%m@=^@sD0CJdAK=`Upbr}?}N zf;snqpt#dOwhxFg82(%Tw=ND+@`O0JGeOWd7-3R8A%Yu%FhiaYXD>p?t2+o%_1CKE z{g(>=g%}X(O%M!}KZK%$7-F<34wD-24`y$WLDv6z?ty=_b)Oi*x&?v}3j0f`AV3HL zWPAYw!XNs-1EmZ9=d=$6LAJISVJ4&gQM5=bh{!f0OmFNz8oMnGgOl_RK5VPP3@87C zpLS$muCo5YTmOslSjFLb`AXIJ@1|O{pm5r z9MxUb-8HMe*|TpFa%dE?+7}MVQ-A-N8wvtq85ROU2%KYt4etC52X0%W08haQgGSU| zvw=K$djTYSLy@4My_Te_8JcZp8Oozg{-ey>*Nm7BkGrX(M~HU6N16U>DSj<`;cy`u zR?0B23zx|*o1V=#fLZ=wd6*NfWjC`pqA^mt>DTZjGBeX`0ZK>Qgxz+37Dyb#NT4WT zl@7Lmh{WdY*h%e_bo6(oXKw=`(9=mft10fOR4< zCOUungtJZPAM~qw4Ydy9PhvYTi1ZRqR5nY)?OX2O3FJ6VXy&`&H%^U|d>N>@f zQ}Cd;DV}_bNiVTW8HcUJDRvXCUwGx|(r2-KbXY>jpd!~jmt(

p*eWM!w;MI3hb2}DlKZV3$r+FsPh`1u zZIhE^SI{5xAuy z+6s18Cax7>1@Y#i1q$NF_)Mm4=(dAqT=saVC z3ws?DY|72z{D*xEl#|0weiXdOyz;mQF%odcChZxu=xzy3zt9$`P-=&#C8aI?6n%3_ zz5<`IpS1r9aqk`~?k)EH2L|zR(c4Uv$Z2a7olc=EI=84->IDAgQ0O!c?s;j~GwDOV zK+prKX=xdIJ0N3!LOV2$b)N7Uaj>3E@S6-{hjDvE>t}L0kZcXl=YV}q=M|8&#+IV% z7RD^fabFCVe->sNrUPX?l52oFvgCj*D!(yOiEb6ol7ttL7T=<BUI`ejr zgg*+ZP+8(22v|(^48*#}u^g}B3f>xir^adn-`lmfOb<^G-!y7%`k3IZ`#M zB{(rrRg$?dR!WsBMPBXZhE#(*5aSeOsDc}n@*FavsCX4WLSl+8v?3`toT5z?Tru|% z6?^pxQ6s6!8MuxUMnH2qd1lR2{b+Z7{vwZ;`Ts(=fC zfROnoU9kNpRnRWsf)bQ~o;_|;`3e3h0#0{2iZq`)?zha}?%a*6PcgK1jgmijN#M&dYfe=TeRB#a0%Y3Of-H;!G z-nt(l!?_lU2Lp5&eSC;vz@;ZmG))Y7eVe8d>|(`l`0BrmtG9x4ViWwD)_yVm{NN+$_Iq_fR=NdfKXQO9!4q;TmDTPWEhSHC(H4OP- z5**=I$LJrFaxI9{BXMC!X@#$%I3AX}cp}#yj9^kX({mj|U&A@Xm1Nwj>YaO(b&FH$cCc{u$!BM}fBu4imE&Nr$UwbW0Ai?7U`GlSm}-%GfbhuDvw`ysfRC9Tl8_e1vG zFc(_hSkSZ5_t6T|zTl5;1m6_vxp zv8jFu#m0PB;MT-~Gk4klcW6H^X7>#l0>YgboQ*~e z(u8wYS#o)gVFUiQxT|OO)9)TMV%9Kc#|>bxwuS=01d_9T7uAo<%BQl>XCs?x7t$XZ zbQPJ4DwJIxsIRGGb4cYt=DPl@9VXctOQ}0cp*zc_yWwotnlC-ebqe}TpZaSse6Gsx zvhDY})0FSKSJqRno1PC+x0=UjjLQ={Nbu$QnRc=>JNSospB?U#tf2Q3!~Koe!2KGf z?@-Lvz;C>#I1+5%tr)>>l9y}3_wPtQ)c8Q+L@GMM-In1m;wpxXA-pC^cS zVTO+a{P)rRGv9U;P(^SR-V?$7o3`L)OxNw+?`ssxry*L)S1OE;^P#0{CYbjHP=D8R z4cy0N(2FvP${xWJieTmtDD{a+@SR{w1--L?dW-c+a5UPkYzK+mTLQ_65XusjT?JRk zB6J9|iiBu4&%`j<@P&n1weU%{grol^4z1RQ${fj#X*2{0?XshpYqAz> zCUrEjg=}fFhEioTHkL+hq;9yvYZdls)}J>l+>X3*ATV>LLZor;SdHKs~>D&N01H-%VlfQl~aT)oDl zW11w^joAb`l@;o!(BxZO*NN(lEQaDMex6SH`@FWk$cyz3wLzg*LgAAZU!48k*xJGh zOJ8;JtEE%*gzD5V^wz^3^*YX#z;$Xi$<#+sf8;BD>rnLVH)YVQvvBB%!|-e;0|u7^#EtDm+1(w zlx6!HBqj+PiySwT^SB$zTL#P5oA(+~?n0cja>E{cW|H&RaUYJ0L99_Oild`1crHq| zY?*Va+O0{@(=N9CDM}IRI$2A2(QR_9wnOGRJb2n)8q(G*=V+)}yw*olX)y%Ti3yak zlpS)x5B+oCKhd=vtFq0m*?pifv53mPmejslmfNAUjZC3)hCNaIpP8R60N<4=dRaJuIOQWc>5tI1pi z1C*g5^!@?^-UI8cMJ$pT{@RinnTv#g@DIZK<){K3TZV zsaV~_btV*zT5TSN6*4adonBssH$nkp$)s~K_(QK6kTO{iP;0%$`rc5VR!`~Xv24eW z!hqX+=jd7yp=yUGuNcv8!J=+I)>+$8!@a&zxA&8@XTek)*{t37{UadA>{^M!%pix!xr2zD#!Ys5{XQu-g&!%3 zw&9oqNIF>cu3|T?!5C_Z0Z%m`Z=686&VgOVKAS6dWR>De2tVJCnm_&1$N9?j&E8oP z+0nu4qUNJ=h3T=gk|jk9?ctjK>IuT5aX{hnE_Z7;kbJWl$o$JdFA5QtXFXHCBE1T{ zQBJ=m6<+P0Gyg&4l|8})S;B05$O|fG(8HNEC{SE8a^%=v>$*PZ#SocA#ztCfWhcj3 z$RIyTH)ozAZbrf>yT#H#-nB4~B?`B*+#^v&YQ1;pDwhHdtBuB^KQ6yGK=#5WZ&gFP zC|FinN3zcEuqU=?8n9loUoLY5U+4bYCWxp(lbJ7d7(aea88Iw4y>7pqZxk1WaAV06 z)Iqn(u0BPsM(nNG&ZxjP^~Sr3O-(jhWLI%Y#iv(6&aBPeytXZkUQTcHN)!gjgG-JS)z^Rn9`; zC<0~P`>qKwWogD?a9{?jKI*1+v-Uz$&^8E~|{zX!{2OsMF_- zW@v&)Zd_x=K)1KZWS+XgHLl;f`0Q5V`YmXI)5DZ4Rp!JBShI3Q>HG$te(N@G5*5KT z+B0~ABi^7U?Y1`%rd{{VbmR~4Th&X3#B96n6zu5(Yg6^j7F5GseLk@oR*ROm_Qd9L zaq6?TRiKc?XyE~Ztp_X$?aJnf@w`b6Zln-b zIqz}?)G1Yth90DGU(O!TcBxf;$dlWnp~$l@D0-*i`M3v!p)CdHLB{;xMJOqi(|W0liNk zO-^Ow=C5j!&Saz-jnHIB^g@ao;{U}kd7lqC8vs|{gGo%&PW7Bg>*oh++|pB&)gH5RK}d462GM?XrMWOq&rku3Ez=suNUiy4gdkH7+69=&YKrrP72W;* zQda+U23SxkJQZInRk3@L9!`=6f3H0zD+??(xAetJkgZ_qo5Q?oN3@%x_ZFF805a6YBmV+@P;MirfnQJWH|0$aW&tWrrsdl_l-zYf|??SBf zJd;pYsjiJs{`sj2l=A{(X=Z>lf@oQpqqd?{VpFp4`rDNLvd8g!zO~}KGyO6mRXq{> z^v9h_)i_VPgmbaMSRqO1PYvb4X{`rIouixL<)3uH?1SK1ZFqr&9oVY?Ep;N_&w}F_ zg1s#v@kZ%CM(N7RL*zepXU3)~k?n5Tp;$FGchUyJb2Q5dLAkrZc;%;XFRU6HI~JD6 zo~EeA!%NP%Lh|}H)5F_^*;D~(yzOK7*EDr~Dt1lQkLnl2m8*&vcQ6x(!Xj&Bw3#7J zNKK~I@0#V_a0GxRlWGU-v|vEfRQ9!}$o*((#6$FHF#ex%i(*ax39#x^I}Ucz8%|bB zBzx-Nd9lR{hd#FA=73GaRc*WMuy|g* z?%?Rwo3mgolttaH(QJ1I$SR;p)t=Q$itIs*A>>ep&Xz0n$$38tr(BEwbL@p2-a)rP(fYNMm>U<>@xg&kP z$wU@jwaeDP`^00h_2nWhzr%m-YiL-=ETegvRa3Gy+)@&0$N&50ZL zDK*$459PvD>Fsh2E$SeA2cIDg8aXZEV%3S6SUk+^STZ z4CCYH8w&TvYy88T23Mxc_qXO~=;TnK+`gQ)H?^5b$41Avsv{FBjt8 z@mooKTAqpPlzl#3V%x(eaa`=5#n9t;Eo!{3U_w^dj$;x{bNhWwlY z?qF7(3mqNNwy0PqR7x#U{+3ZyzhDBeZs-Lxrivnt@(NMLne@T<;NN( z%$5RMP6K1&y3B|+L^qG?j`)ipgdwb$lU@P0^+KjbG1M#kieWK2oy&!CsbgNfD7BMo zTA14eoWOM#PLx2Od?op(G)5Ev8nZPfV`+poQkSV1WjTs~pa6C!mhw#oTWOvR$3yY( zRpMUQ(!@*U)z*!!dW+@qdWGZGFAs0Us;rd7fI=JP-fBIrEd#-YIe9|R6kHbTxQmb{ zn<_=!j=u=jYl%LWkm}Q9C)opTT+l9WurhgHYJ{kXQEv8z~v{ELf;%baSF;Oh^gc}i6l5j&M&y>=+a*-sOWv&d0+ zqa#Gefl7@qQKo*^7$-z(FED@Vlyr-d6Wx}n#Vu^b%j`v15Lb+ugv0K?L}rkQ+M?I? zBv*@Q#tjEa$t+Ar`IoX!^*_4{zT-(B4^F0N9edgkurNm-sEqY$@|RioV1#-)E<%uA|I z^%13Gno@-HyRoh{DGDH7PRfY+Q?ybt$7CTCxq% z$SfaEz+$MY#i0MMFzD|*)|rn90r8Ci0^-ZR*Axl7B8&hUxmpI0BA)p{31jz0L*)y9 zMo0VvhYG3cLC!QXOn*H=5LaB$DCS_HtFZRdr6L?bRZ+5=dR1$wbfL7NLL29zvO%p( zjcx0rofDWsj`9ig!*`_P_lDPHi`jFQ(^Q+sVFWA+`i#u`xcrfQG+SRj9;0j}8(Hnl zz9djd57HMzyR8Tx84DsE(Fp&@ zzEUBWG&N59MO6l$VQxqSK zDN2A>f3*;B9ayKeP?L5Fuhu3bwDfLQ6JMlh*W1w|$vWNR!CT%gqG(r4t$ICi5s=-P z!x9i7=6pUeUVN+n$w{a4yGXUy2b%LqBPmJT;*e&2zsP01+;~JS*S9p`S7;W; z4K)c!q98^RI5oxKofw1ki#v0Il1j9$LclhmQx?in{mEL8Jwi9_IsMZeX%^iCC+2%$ z)>rRvwj;QmXLykGj@|1B>T2B+Z>@eBwU>XEz%IhUy|BkBBXO(3P6TFWvSdZ%pezF+ zqut_JlSY-|1~rP+bu+OUJbi^mqr2|HDlieGwpgyK++w`3I;y&0R<76X%B?K7kg}>) z!B#GoCS@f@8BpW1;;>}sT~T=Yv`|W5d!2exx_Oifnc?eT zg`X~j4V!Lglo=@Tp_VQ6p0SgW{~i%)S|R*-G{|*n{fa;PdWNJ6yf4UU9%0*34A5!| z5g`zfg%bga)ExgTX`Bm7(>f2`+m<22Kd%CQ#jL2W4QbcvuX7M_9sd)P`!<9 z$RoS5(db}dBa{r;t7JpJ7DaR=OT!BTT?00P89YdSXAHA7&7xmz<1>4sS*o2ZJ&Z=i zy2QadKJQNoxLL`RFu2zvldlG#65=XOVTQ(l4J1;?QIwizBLN*PtlIM3CQYUoG5sO5 zj=X{n3M`f$0R)@}Y_AzW5Yul(AYNOdhQsxF`p@@pB1MP52J{-A&nV{irosr?TqDs# z=;9r=Vto)D6=GGK_b^t2IE|m+R0AgUM^!e+wm+S0M|DVIdBUg72d3tNQd5|#pYO=7 zPR)?A$t%;aZ2WR*V00=7ekt%VUP(Ya9KeXxL8X$-?Q!JZ1+%v<>YL3rub@gNTRdrL zGezK`O|UTl+;CG+ytO#UBFu1|8qmP$?c`|iYw7msv(@iVta*>&(W)o0y0H&k4Y{o0 z3{j#8k(rXL(=bXN^yo97+|LqNqAX;1f$%>*frED&a;PVnk56fnTR&M2>@K82FtrJx zoW)ro!M^$_gi)2(K`ZS}sBa;6j3 z!X^6G)ML_=3!9P`^+2A)llH_J*3ug3%;r|Z!`0rfCaa2Kpz&vbmUI&}E@5<$aSqN^ zGRM!l+K?nWm3D~We?ZqS4r#3d9dYLB0YmAB^qEl{8j~hFBUspUFYIHj;6nMV$@zWv z`GU!Tk16kj1rFU*yxH;dUxtm}cf7X?^X=Cubg2q(C(y(ZVlos>i4u0%ABWqclkJt- z58dsf+x_)$r*g2Hh8?FEyir2U#U=xH6*? zX9dS_3)(6CxK_?u_}25=OTlo@GjHZZ_7~qVW>y0xK&xu}&6-PjLdp^K-{DZLky0k+ zZt@mG{L$c2CsM=2QRE!xUyGo$BXO})FNBU~7`;}G=_PZWv>b_Hkfi=#AP(d-k}d{} z5g1D<0KaIlLIZRcT}KXj#L2MzePqbcaO9T@me~~PlQlPC6f+W_Z}*;OR2Y$@Y-p4p z>{pZSK_j#^<2UfjP&nEJdR=e{AV!v_=27`8FuY*F&D>k$XxFxxBFx?X>OgQ#gLJRz zGqi@PLmfZ11yI&Z@H zHaVeBn@rfA&lGvFCis^s#t(6}Hg#xLpoXrmig(flx(b>!9pIjHTOoxTjuTV6ix5ni z3oj(rS`@{>f!-^?P+8#iuk%Ug!5W=c?*iWVbOA%{tZx?go{TDQ+0s9XtY1fiH0{cW z8XPCF^3GN7A@4wa?qGC1$NvP6?DsPfX2#Q;t8ZseA9RYw z=)T^q7qD%$7gv%H%Q!QeouXuA&>fuKM2ZJ@`Lo1v09fzlTVKfyn_P3i-^AYnoe;fz zz1vnYV%^Bh;1xEpU*_g4k1dm{Jo@C`GM@X2Ejpe`-@d2{=P2A*qY{ z!*E9J+scte+VBh)ZAkRTEuEK`2c+FgKzwdiQxD4M^^v4E1-xjDNvY_v7n&yT`u8ZU zsak|l(?S>p1^;rG#9`*2`L$?fdb3u8@;r04yD%kuO^R35-IM5OX7EFGS<~YB(49V= z*(L0DGeMYllq{bZ2YF-MDq(@yc1pH~ImFs5fsIF_GKjT ztjgq}U{T>qdsc$*bwLRaUakca#JPh+r++`TNVZiAc9fXnQLv4P1SXeGhsHBMV>IRt z&|%tXD!<;66ayMbj+kyA7#-Cf*}nAZ>6(8_6mrg4Zbs|zgECJ*5=M2gV7b=_KHgW| zD$YZ_@RAg$6B#fu$_WX61~J@kzSh@B;0#}=mjdbpf@5e=@)<7xAsrX71nC;!41RSg zI#A(=!~jT0is6st zVr;A#33q6%{hLssmFHF-lI`Lyol&qJ+9KK2CqKb2rA;X#OP!P7K~!YWhqZRZ9lsbJ zHr%se#s4slO95RjT~>1 zCiZVKJA)Ac{Q9NU9T01M-f)ELS2Y+5E+SYw${DWFp*iDLLSPVweCy9j^4d&M%EnC5 zQu;H=eMbXlSluABU#5c3l0sd@#Q`u?qQLytt55iWAvq?Oer*AcqkOYSbhn1y`rT_{ zeP{5Hn|?*j#ra@IUi1FEcsDx|?jqqKVSC2latgN8LZO?JL{R$J#m1~7V{X|A{`dWy z=R2R5Pt8vj9Dh*N91UzpFY-x*>Sm^Id0L58Ff0%^{HT~VLKkey+u^LP`0dX6jts|R zQV<-)FN?ZI8Sz!s=Oy#Xbe%RtLZ(GJS>-Ev&tUMC(XX7RlUpuz9`84PQHmL zx;?H95V2JvYJsAw&hqtBc2m#B?xEXZ?FvssN_e*??k8RjeNz<@iH0w;!!8LdzJ0@E z?Ffi2L!xG7D{)PWadQ(SQQ)EeF}_xC{_;1gkV4bJq;BvB$ez$Ou=x&TUAYy?9^ zPh(vYIJ!=OZUuCkq3^a=vzfFWP^vC2oQ(44W_QVqOXacaW`IxfxXf$$x$80g^3-8b zjHUI|1t7T0{uFw<6Iu;nXw6EV8T9TR>hx7q6COg>RxBIGi1yF?s0<`(h+rSs7#v>D zP769_q1zh)i~dNwzjLCK`d#Pv6$BHU;wc~}pTCi1lH(+XGa;dnAepFH4aUyZ)N|J) zw!&*ct{?#UISa*_spr-)G}-YQu|G#N7yuewxg+O?hW?_dHG?JD^jfWyo{`{M!+*mp zF1qv8(S?kPrlgsxczW*1B-uQ@dm|we;u@&t`Ud@;S#Wf&3;}bel`9ymylurh($N%g za~kd_cb-2$*U}o1IPXDHc*CPUsq`dJ1jvMiNL+B9m2}n8i>^o9QoqbM(XG#|i~z}1 zf*(uev{ob+;=0v(7RwAo>|isL)DOLW-T7)gl!Kg2~BxL41UDz>AiDTe`R#Ep-R?Go6fW!u{ zfi2&FdnM`?dip|53_v6)WKA}O%LV0NUsuD$t^q^4%f&!ZM2e#?M<&@modn$@rRl2t|U`T|lC7_@5< zmd5nd&B217g(u2&z{U8|3=I1oy6B(ps*h^DmCXre7XogQ7m6R4zgpb-sB8%#sfuxX z!m^ug2opaNFJ(G=A8G7%Le2aL_W1E>{YOJ2OYdQrae2H)<&6}#k z{mNH^&m*3<;pNO}!Ic&TRx_Yw!*o{+c!qD-F&S{8u5sFOqq_SJ7b}OtpF5#vHTl2F z*6+TuYrMO}ovrLB(37m;7}goKPvr|1kuj5~fbs=}!i1>5@BfpVCyYJQHfu1GlOFo` z%3B3Wy1zO4$OT}&AjJH^l&RhSAu)pSA!g0^t3EFx^`IPO<-36LWC{bwaWe1<)wG-5 za7f0P>LAQ<;08UwlW6{@f_q8Cq%a|#OUEG(&88$}c$S}bF#0DuDw~94%MDq`i(^Y9 z>X`G(PAv`_uu#@L<`sV}j#Or_$fln&46^gdABbnyyETV*Yk7ide0{PPSktWn(mSU8 zvqyt;6#e#(X}CMmoBJWq_8pD8k2p*A*tf0dcbyl)w^j=Rgdy8j#6Jn&g$>WytH;QB z65f$JiOY%QKcL*0o|Xc_f7Pb7FWXbU znj@lQe<@=NgEdWmd$y3?@0)bfOdKxy=rMG>iD?=o$N7>5JGPZrA1I|6lFzp47V6j{ zaZD=Uet4Tdjio^WN>qc7ub7%-O(%$61YK`y4SEwzRR4_5WgmtQ0mFrAcw zv8VCOx%uwvYFe=h#bHJ7TC-+Q^LUKywVbA-lPII1SC;RjXG2A9r$tv)f%Qaf9{@@6 zm}#^Ro_NnsQSal4!}ehY3P|gC5pl1ONOrPOk#Mb;M4?0p>n=V)pp4w5V5@(^qH;6k zw!1yJY!~Ru=!Qqx?U5VQH`@$hfiby8%{j`slSQ~?+z)m-CJ5cwG5$E;4dW86`#`Dl zR)+>b|Lu|n2QOL@{#O&^KW&l!`{nz8Mh5%SWBqNPrd^^Y{J))U5D=vQ>-uNR_jg47 z*Z3J6vBV6hAo&knUHS&d`0|&Iefhmj@^~fw$LH0Vz&k&JA9`@ITB22u9sR1vhQr1C(9= zp?Ki)4LJam7kDS05UjB&1W5J%3nzV1{u&oI@c}PBeL^e2h{yt0J~uHVK7;Ku%yZnxzDBXR#gL9qNjDj2+j z54cPD8(~T(0AK9T0&dg)(r-mDV74smzb^A#e85xIf8>f?9>C|k|4_*Sw7)Lk9zFoN z;9nX2@8Kep{=b{{srcU@B6w?$2XIyTmkR9j0z@nRLQoa)-NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From 712525065c41f6560af1cacee89aea218587ca08 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Mon, 31 Jan 2022 19:03:44 +0100 Subject: [PATCH 004/218] update dependencies, remove deprecated properties --- build.gradle | 2 +- .../manager/payment/MollieConnectManager.java | 5 +- .../manager/payment/StripeConnectManager.java | 6 +- .../TicketReservationModification.java | 10 --- .../PollApiControllerIntegrationTest.java | 2 +- ...dminReservationManagerIntegrationTest.java | 28 ++++---- .../CheckInManagerIntegrationTest.java | 2 +- .../ConfigurationManagerIntegrationTest.java | 36 +++++------ .../manager/GroupManagerIntegrationTest.java | 8 +-- .../ReverseChargeManagerIntegrationTest.java | 6 +- ...icketReservationManagerConcurrentTest.java | 10 +-- ...cketReservationManagerIntegrationTest.java | 64 +++++++++---------- .../WaitingQueueManagerIntegrationTest.java | 50 +++++++-------- .../system/DataMigratorIntegrationTest.java | 20 +++--- 14 files changed, 118 insertions(+), 131 deletions(-) diff --git a/build.gradle b/build.gradle index 9249300a21..61220660a5 100644 --- a/build.gradle +++ b/build.gradle @@ -151,7 +151,7 @@ dependencies { implementation 'com.atlassian.commonmark:commonmark-ext-gfm-tables:0.17.0' implementation 'com.ryantenney.passkit4j:passkit4j:2.0.1' implementation 'com.github.ben-manes.caffeine:caffeine' - implementation 'com.github.scribejava:scribejava-core:5.0.0' + implementation 'com.github.scribejava:scribejava-core:8.3.1' implementation 'ch.digitalfondue.vatchecker:vatchecker:1.5.0' implementation 'ch.digitalfondue.basicxlsx:basicxlsx:0.5.1' implementation 'org.imgscalr:imgscalr-lib:4.2' diff --git a/src/main/java/alfio/manager/payment/MollieConnectManager.java b/src/main/java/alfio/manager/payment/MollieConnectManager.java index 9c4f314203..1712385c8a 100644 --- a/src/main/java/alfio/manager/payment/MollieConnectManager.java +++ b/src/main/java/alfio/manager/payment/MollieConnectManager.java @@ -27,7 +27,6 @@ import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.model.OAuth2AccessToken; -import com.github.scribejava.core.model.OAuthConfig; import com.github.scribejava.core.oauth.OAuth20Service; import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -56,8 +55,8 @@ public AuthorizationRequestDetails getConnectURL(int organizationId) { var options = configurationManager.getFor(Set.of(MOLLIE_API_KEY, MOLLIE_CONNECT_CLIENT_ID, MOLLIE_CONNECT_CALLBACK, BASE_URL), ConfigurationLevel.organization(organizationId)); String callbackURL = options.get(MOLLIE_CONNECT_CALLBACK).getValueOrDefault(options.get(BASE_URL).getRequiredValue() + MOLLIE_CONNECT_REDIRECT_PATH); String state = extensionManager.generateOAuth2StateParam(organizationId).orElse(UUID.randomUUID().toString()); - OAuthConfig config = new OAuthConfig(options.get(MOLLIE_CONNECT_CLIENT_ID).getRequiredValue(), options.get(MOLLIE_API_KEY).getRequiredValue(), callbackURL, SCOPES, null, state, "code", null, null, null); - return new AuthorizationRequestDetails(new MollieConnectApi().getAuthorizationUrl(config, Collections.emptyMap()), state); + return new AuthorizationRequestDetails(new MollieConnectApi() + .getAuthorizationUrl("code", options.get(MOLLIE_CONNECT_CLIENT_ID).getRequiredValue(), callbackURL, SCOPES, state, Collections.emptyMap()), state); } @Override diff --git a/src/main/java/alfio/manager/payment/StripeConnectManager.java b/src/main/java/alfio/manager/payment/StripeConnectManager.java index e1431134cf..86302ae041 100644 --- a/src/main/java/alfio/manager/payment/StripeConnectManager.java +++ b/src/main/java/alfio/manager/payment/StripeConnectManager.java @@ -29,7 +29,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.model.OAuthConfig; import com.github.scribejava.core.oauth.OAuth20Service; import lombok.extern.log4j.Log4j2; import org.springframework.core.env.Environment; @@ -64,12 +63,11 @@ public StripeConnectManager(ExtensionManager extensionManager, @Override public AuthorizationRequestDetails getConnectURL(int organizationId) { var options = configurationManager.getFor(Set.of(STRIPE_SECRET_KEY, STRIPE_CONNECT_CLIENT_ID, STRIPE_CONNECT_CALLBACK, BASE_URL), ConfigurationLevel.organization(organizationId)); - String secret = options.get(STRIPE_SECRET_KEY).getRequiredValue(); String clientId = options.get(STRIPE_CONNECT_CLIENT_ID).getRequiredValue(); String callbackURL = options.get(STRIPE_CONNECT_CALLBACK).getValueOrDefault(options.get(BASE_URL).getRequiredValue() + STRIPE_CONNECT_REDIRECT_PATH); String state = extensionManager.generateOAuth2StateParam(organizationId).orElse(UUID.randomUUID().toString()); - OAuthConfig config = new OAuthConfig(clientId, secret, callbackURL, "read_write", null, state, "code", null, null, null); - return new AuthorizationRequestDetails(new StripeConnectApi().getAuthorizationUrl(config, Collections.emptyMap()), state); + return new AuthorizationRequestDetails(new StripeConnectApi() + .getAuthorizationUrl("code", clientId, callbackURL, "read_write", state, Collections.emptyMap()), state); } @Override diff --git a/src/main/java/alfio/model/modification/TicketReservationModification.java b/src/main/java/alfio/model/modification/TicketReservationModification.java index ff2afdf08e..9688f8a6d9 100644 --- a/src/main/java/alfio/model/modification/TicketReservationModification.java +++ b/src/main/java/alfio/model/modification/TicketReservationModification.java @@ -28,14 +28,4 @@ public class TicketReservationModification implements Serializable { private Integer quantity; private List> metadata; - // temporary until we replace the public front-end - @Deprecated(forRemoval = true) - public Integer getAmount() { - return quantity; - } - - @Deprecated(forRemoval = true) - public void setAmount(Integer amount) { - this.quantity = amount; - } } diff --git a/src/test/java/alfio/controller/api/v2/user/PollApiControllerIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/PollApiControllerIntegrationTest.java index 55030dfa19..52ea19df7e 100644 --- a/src/test/java/alfio/controller/api/v2/user/PollApiControllerIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/PollApiControllerIntegrationTest.java @@ -119,7 +119,7 @@ void init() { pollId = rowCountAndKey.getKey(); LOGGER.info("pollId {}", pollId); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(1); + tr.setQuantity(1); TicketCategory category = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0); tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); diff --git a/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java b/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java index 05bbc4b2ef..77e8ef28b2 100644 --- a/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/AdminReservationManagerIntegrationTest.java @@ -60,7 +60,7 @@ @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) @Transactional -public class AdminReservationManagerIntegrationTest extends BaseIntegrationTest { +class AdminReservationManagerIntegrationTest extends BaseIntegrationTest { @Autowired private AdminReservationManager adminReservationManager; @@ -86,12 +86,12 @@ public class AdminReservationManagerIntegrationTest extends BaseIntegrationTest private ConfigurationRepository configurationRepository; @BeforeEach - public void init() { + void init() { IntegrationTestUtil.ensureMinimalConfiguration(configurationRepository); } @Test - public void testReserveFromExistingCategory() { + void testReserveFromExistingCategory() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -101,7 +101,7 @@ public void testReserveFromExistingCategory() { } @Test - public void testReserveFromExistingMultipleCategories() { + void testReserveFromExistingMultipleCategories() { List categories = Arrays.asList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 10, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -115,7 +115,7 @@ public void testReserveFromExistingMultipleCategories() { } @Test - public void testReserveFromExistingCategoryNotEnoughSeatsNotBounded() { + void testReserveFromExistingCategoryNotEnoughSeatsNotBounded() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -125,7 +125,7 @@ public void testReserveFromExistingCategoryNotEnoughSeatsNotBounded() { } @Test - public void testReserveExistingCategoryNotEnoughSeatsNotBoundedSoldOut() { + void testReserveExistingCategoryNotEnoughSeatsNotBoundedSoldOut() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -135,7 +135,7 @@ public void testReserveExistingCategoryNotEnoughSeatsNotBoundedSoldOut() { } @Test - public void testReserveFromExistingCategoryNotEnoughSeatsBounded() { + void testReserveFromExistingCategoryNotEnoughSeatsBounded() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -145,7 +145,7 @@ public void testReserveFromExistingCategoryNotEnoughSeatsBounded() { } @Test - public void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedBounded() { + void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedBounded() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -155,7 +155,7 @@ public void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedBound } @Test - public void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedNotBounded() { + void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedNotBounded() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -165,7 +165,7 @@ public void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedNotBo } @Test - public void testReserveFromNewCategory() { + void testReserveFromNewCategory() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -199,7 +199,7 @@ public void testReserveFromNewCategory() { } @Test - public void testReserveMixed() { + void testReserveMixed() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -245,7 +245,7 @@ public void testReserveMixed() { } @Test - public void testConfirmReservation() { + void testConfirmReservation() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -266,7 +266,7 @@ public void testConfirmReservation() { } @Test - public void testConfirmReservationSendConfirmationEmail() { + void testConfirmReservationSendConfirmationEmail() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -310,7 +310,7 @@ private Triple performExistingCategoryTest(Lis if(reservedTickets > 0) { TicketReservationModification trm = new TicketReservationModification(); - trm.setAmount(reservedTickets); + trm.setQuantity(reservedTickets); trm.setTicketCategoryId(existingCategories.get(0).getId()); TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); ticketReservationManager.createTicketReservation(event, Collections.singletonList(r), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); diff --git a/src/test/java/alfio/manager/CheckInManagerIntegrationTest.java b/src/test/java/alfio/manager/CheckInManagerIntegrationTest.java index 63df114e00..2e4846388d 100644 --- a/src/test/java/alfio/manager/CheckInManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/CheckInManagerIntegrationTest.java @@ -114,7 +114,7 @@ void testReturnOnlyOnce() { var additionalService = eventManager.insertAdditionalService(event, additionalServiceRequest); var category = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(AVAILABLE_SEATS); + tr.setQuantity(AVAILABLE_SEATS); tr.setTicketCategoryId(category.getId()); var tickets = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); diff --git a/src/test/java/alfio/manager/ConfigurationManagerIntegrationTest.java b/src/test/java/alfio/manager/ConfigurationManagerIntegrationTest.java index 9de6151764..f9098e1169 100644 --- a/src/test/java/alfio/manager/ConfigurationManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/ConfigurationManagerIntegrationTest.java @@ -64,7 +64,7 @@ @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) @Transactional -public class ConfigurationManagerIntegrationTest extends BaseIntegrationTest { +class ConfigurationManagerIntegrationTest extends BaseIntegrationTest { public static final String USERNAME = "test"; @@ -90,10 +90,10 @@ public class ConfigurationManagerIntegrationTest extends BaseIntegrationTest { private TicketCategoryRepository ticketCategoryRepository; @BeforeEach - public void prepareEnv() { + void prepareEnv() { //setup... organizationRepository.create("org", "org", "email@example.com", null, null); - Organization organization = organizationRepository.findByName("org").get(); + Organization organization = organizationRepository.findByName("org").orElseThrow(); userManager.insertUser(organization.getId(), USERNAME, "test", "test", "test@example.com", Role.OWNER, User.Type.INTERNAL); @@ -121,33 +121,33 @@ public void prepareEnv() { } @Test - public void testPresentStringConfigValue() { + void testPresentStringConfigValue() { assertEquals(Optional.of("5"), configurationManager.getFor(MAX_AMOUNT_OF_TICKETS_BY_RESERVATION, ConfigurationLevel.event(event)).getValue()); } @Test - public void testEmptyStringConfigValue() { + void testEmptyStringConfigValue() { assertTrue(configurationManager.getFor(SMTP_PASSWORD, ConfigurationLevel.event(event)).getValue().isEmpty()); } @Test - public void testStringValueWithDefault() { + void testStringValueWithDefault() { assertEquals("5", configurationManager.getFor(MAX_AMOUNT_OF_TICKETS_BY_RESERVATION, ConfigurationLevel.event(event)).getRequiredValue()); assertEquals("-1", configurationManager.getFor(SMTP_PASSWORD, ConfigurationLevel.event(event)).getValueOrDefault("-1")); } @Test - public void testMissingConfigValue() { + void testMissingConfigValue() { assertThrows(IllegalArgumentException.class, () -> configurationManager.getFor(SMTP_PASSWORD, ConfigurationLevel.event(event)).getRequiredValue()); } @Test - public void testRequiredValue() { + void testRequiredValue() { assertEquals("5", configurationManager.getFor(MAX_AMOUNT_OF_TICKETS_BY_RESERVATION, ConfigurationLevel.event(event)).getRequiredValue()); } @Test - public void testIntValue() { + void testIntValue() { assertEquals(5, configurationManager.getFor(MAX_AMOUNT_OF_TICKETS_BY_RESERVATION, ConfigurationLevel.event(event)).getValueAsIntOrDefault(-1)); //missing value @@ -161,7 +161,7 @@ public void testIntValue() { } @Test - public void testBooleanValue() { + void testBooleanValue() { //missing value assertFalse(configurationManager.getFor(ALLOW_FREE_TICKETS_CANCELLATION, ConfigurationLevel.ticketCategory(event, ticketCategory.getId())).getValueAsBooleanOrDefault()); @@ -175,7 +175,7 @@ public void testBooleanValue() { } @Test - public void testOverrideMechanism() { + void testOverrideMechanism() { Organization organization = organizationRepository.findByName("org").orElseThrow(); @@ -208,7 +208,7 @@ public void testOverrideMechanism() { } @Test - public void testBasicConfigurationNotNeeded() { + void testBasicConfigurationNotNeeded() { configurationRepository.deleteByKey(ConfigurationKeys.BASE_URL.getValue()); configurationRepository.deleteByKey(ConfigurationKeys.SUPPORTED_LANGUAGES.getValue()); @@ -221,7 +221,7 @@ public void testBasicConfigurationNotNeeded() { } @Test - public void testSaveOnlyExistingConfiguration() { + void testSaveOnlyExistingConfiguration() { configurationRepository.insertOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue(), "MY-ACCOUNT_NUMBER", "empty"); Configuration existing = configurationRepository.findByKeyAtOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue()).orElseThrow(IllegalStateException::new); Map> all = configurationManager.loadOrganizationConfig(event.getOrganizationId(), USERNAME); @@ -239,7 +239,7 @@ public void testSaveOnlyExistingConfiguration() { } @Test - public void testSaveOnlyValidConfiguration() { + void testSaveOnlyValidConfiguration() { configurationRepository.insertOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue(), "MY-ACCOUNT_NUMBER", "empty"); Configuration existing = configurationRepository.findByKeyAtOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue()).orElseThrow(IllegalStateException::new); Map> all = configurationManager.loadOrganizationConfig(event.getOrganizationId(), USERNAME); @@ -263,7 +263,7 @@ public void testSaveOnlyValidConfiguration() { } @Test - public void testLoadOrganizationConfiguration() { + void testLoadOrganizationConfiguration() { Map> orgConf = configurationManager.loadOrganizationConfig(event.getOrganizationId(), USERNAME); assertEquals(ConfigurationKeys.byPathLevel(ConfigurationPathLevel.ORGANIZATION).size(), orgConf.values().stream().mapToLong(Collection::size).sum()); String value = "MY-ACCOUNT_NUMBER"; @@ -274,13 +274,13 @@ public void testLoadOrganizationConfiguration() { } @Test - public void testBasicConfigurationNeeded() { + void testBasicConfigurationNeeded() { configurationRepository.deleteByKey(ConfigurationKeys.BASE_URL.getValue()); assertTrue(configurationManager.isBasicConfigurationNeeded()); } @Test - public void testSaveBooleanOptions() { + void testSaveBooleanOptions() { String ftcKey = ALLOW_FREE_TICKETS_CANCELLATION.getValue(); configurationRepository.insert(ftcKey, "false", "this should be updated to true"); ConfigurationModification ftc = new ConfigurationModification(configurationRepository.findByKey(ftcKey).getId(), ftcKey, "true"); @@ -317,7 +317,7 @@ public void testSaveBooleanOptions() { } @Test - public void testBulk() { + void testBulk() { Event event = eventManager.getSingleEvent("eventShortName", "test"); var res = configurationManager.getFor(Set.of(MAX_AMOUNT_OF_TICKETS_BY_RESERVATION, ENABLE_WAITING_QUEUE, ENABLE_WAITING_QUEUE_NOTIFICATION), ConfigurationLevel.event(event)); diff --git a/src/test/java/alfio/manager/GroupManagerIntegrationTest.java b/src/test/java/alfio/manager/GroupManagerIntegrationTest.java index b53ecc60d5..648bd7d382 100644 --- a/src/test/java/alfio/manager/GroupManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/GroupManagerIntegrationTest.java @@ -61,7 +61,7 @@ @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) @Transactional -public class GroupManagerIntegrationTest extends BaseIntegrationTest { +class GroupManagerIntegrationTest extends BaseIntegrationTest { @Autowired private EventManager eventManager; @@ -93,7 +93,7 @@ public void setup() { } @Test - public void testLinkToEvent() { + void testLinkToEvent() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 10, @@ -121,7 +121,7 @@ public void testLinkToEvent() { assertTrue(groupManager.isAllowed("test@test.ch", event.getId(), categoryId)); TicketReservationModification ticketReservation = new TicketReservationModification(); - ticketReservation.setAmount(1); + ticketReservation.setQuantity(1); ticketReservation.setTicketCategoryId(categoryId); String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(new TicketReservationWithOptionalCodeModification(ticketReservation, Optional.empty())), @@ -142,7 +142,7 @@ public void testLinkToEvent() { } @Test - public void testDuplicates() { + void testDuplicates() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 10, new DateTimeModification(LocalDate.now(ClockProvider.clock()).plusDays(1), LocalTime.now(ClockProvider.clock())), diff --git a/src/test/java/alfio/manager/ReverseChargeManagerIntegrationTest.java b/src/test/java/alfio/manager/ReverseChargeManagerIntegrationTest.java index 801e550cb6..3f377f6525 100644 --- a/src/test/java/alfio/manager/ReverseChargeManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/ReverseChargeManagerIntegrationTest.java @@ -74,7 +74,7 @@ @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class, ControllerConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) @Transactional -public class ReverseChargeManagerIntegrationTest extends BaseIntegrationTest { +class ReverseChargeManagerIntegrationTest extends BaseIntegrationTest { private final ClockProvider clockProvider; private final OrganizationRepository organizationRepository; @@ -218,11 +218,11 @@ private ReservationInfo createReservation(String id, boolean requestInvoice) { var form = new ReservationForm(); var first = new TicketReservationModification(); - first.setAmount(2); + first.setQuantity(2); first.setTicketCategoryId(categories.get(0).getId()); var second = new TicketReservationModification(); - second.setAmount(2); + second.setQuantity(2); second.setTicketCategoryId(categories.get(1).getId()); form.setReservation(List.of(first, second)); diff --git a/src/test/java/alfio/manager/TicketReservationManagerConcurrentTest.java b/src/test/java/alfio/manager/TicketReservationManagerConcurrentTest.java index e10dfba654..1b2cc2c46f 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerConcurrentTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerConcurrentTest.java @@ -63,7 +63,7 @@ @SpringBootTest() @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) -public class TicketReservationManagerConcurrentTest { +class TicketReservationManagerConcurrentTest { private static final String ACCESS_CODE = "MY_ACCESS_CODE"; @@ -121,14 +121,14 @@ public void setUp() { } @Test - public void testConcurrentAccessCode() throws InterruptedException { + void testConcurrentAccessCode() throws InterruptedException { var pool = Executors.newFixedThreadPool(AVAILABLE_SEATS); var callableList = new ArrayList>>(); for (int i = 0; i < AVAILABLE_SEATS; i++) { callableList.add(() -> { return transactionTemplate.execute(tx -> { TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(1); + tr.setQuantity(1); tr.setTicketCategoryId(firstCategoryId); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); return ticketReservationManager.reserveTokensForAccessCode(mod, promoCodeDiscount); @@ -153,9 +153,9 @@ public void testConcurrentAccessCode() throws InterruptedException { } @Test - public void testExpirationDuringReservation() { + void testExpirationDuringReservation() { TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(1); + tr.setQuantity(1); tr.setTicketCategoryId(firstCategoryId); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); diff --git a/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java b/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java index bd2acd0969..f0836a0e27 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerIntegrationTest.java @@ -65,7 +65,7 @@ @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) @Transactional -public class TicketReservationManagerIntegrationTest extends BaseIntegrationTest { +class TicketReservationManagerIntegrationTest extends BaseIntegrationTest { static final Map DESCRIPTION = Collections.singletonMap("en", "desc"); private static final String ACCESS_CODE = "MYACCESSCODE"; @@ -107,12 +107,12 @@ public class TicketReservationManagerIntegrationTest extends BaseIntegrationTest private NamedParameterJdbcTemplate jdbcTemplate; @BeforeEach - public void ensureConfiguration() { + void ensureConfiguration() { IntegrationTestUtil.ensureMinimalConfiguration(configurationRepository); } @Test - public void testPriceIsOverridden() { + void testPriceIsOverridden() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -122,7 +122,7 @@ public void testPriceIsOverridden() { Event event = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository).getKey(); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(2); + tr.setQuantity(2); TicketCategory category = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0); tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -136,7 +136,7 @@ public void testPriceIsOverridden() { } @Test - public void testTicketSelection() { + void testTicketSelection() { List categories = List.of( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -157,11 +157,11 @@ public void testTicketSelection() { assertEquals(0, eventStatisticsManager.loadModifiedTickets(event.getId(), unbounded.getId(), 0, null).size()); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(10); + tr.setQuantity(10); tr.setTicketCategoryId(bounded.getId()); TicketReservationModification tr2 = new TicketReservationModification(); - tr2.setAmount(9); + tr2.setQuantity(9); tr2.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -220,7 +220,7 @@ public void testTicketSelection() { //------------------- TicketReservationModification trForDelete = new TicketReservationModification(); - trForDelete.setAmount(1); + trForDelete.setQuantity(1); trForDelete.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification modForDelete = new TicketReservationWithOptionalCodeModification(trForDelete, Optional.empty()); String reservationId2 = ticketReservationManager.createTicketReservation(event, Collections.singletonList(modForDelete), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); @@ -238,7 +238,7 @@ public void testTicketSelection() { } @Test - public void deferredOfflinePayment() { + void deferredOfflinePayment() { // enable deferred payment configurationRepository.insert(DEFERRED_BANK_TRANSFER_ENABLED.name(), "true", ""); @@ -254,7 +254,7 @@ public void deferredOfflinePayment() { TicketReservationModification trForDeferred = new TicketReservationModification(); - trForDeferred.setAmount(1); + trForDeferred.setQuantity(1); trForDeferred.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification modForDeferred = new TicketReservationWithOptionalCodeModification(trForDeferred, Optional.empty()); String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(modForDeferred), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); @@ -297,7 +297,7 @@ public void deferredOfflinePayment() { } @Test - public void testTicketWithDiscount() { + void testTicketWithDiscount() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -314,7 +314,7 @@ public void testTicketWithDiscount() { eventManager.addPromoCode("MYFIXEDPROMO", null, event.getOrganizationId(), event.getBegin(), event.getEnd(), 5, PromoCodeDiscount.DiscountType.FIXED_AMOUNT, null, null,"description", "email@reference.ch", PromoCodeDiscount.CodeType.DISCOUNT, null); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(3); + tr.setQuantity(3); tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -338,7 +338,7 @@ public void testTicketWithDiscount() { TicketReservationModification trFixed = new TicketReservationModification(); - trFixed.setAmount(3); + trFixed.setQuantity(3); trFixed.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification modFixed = new TicketReservationWithOptionalCodeModification(trFixed, Optional.empty()); @@ -364,7 +364,7 @@ public void testTicketWithDiscount() { //check if we try to fetch more than the limit TicketReservationModification trTooMuch = new TicketReservationModification(); - trTooMuch.setAmount(4); + trTooMuch.setQuantity(4); trTooMuch.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification modTooMuch = new TicketReservationWithOptionalCodeModification(trTooMuch, Optional.empty()); assertThrows(TicketReservationManager.TooManyTicketsForDiscountCodeException.class, @@ -372,7 +372,7 @@ public void testTicketWithDiscount() { } @Test - public void testAdditionalServiceWithDiscount() { + void testAdditionalServiceWithDiscount() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -389,7 +389,7 @@ public void testAdditionalServiceWithDiscount() { eventManager.addPromoCode("MYPROMOCODE", event.getId(), null, event.getBegin(), event.getEnd(), 10, PromoCodeDiscount.DiscountType.PERCENTAGE, null, 3, "description", "email@reference.ch", PromoCodeDiscount.CodeType.DISCOUNT, null); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(3); + tr.setQuantity(3); tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -417,7 +417,7 @@ public void testAdditionalServiceWithDiscount() { } @Test - public void testAccessCode() { + void testAccessCode() { testTicketsWithAccessCode(); } @@ -438,7 +438,7 @@ private Triple testTicketsWithAccessCode() { eventManager.addPromoCode(accessCode, event.getId(), null, event.getBegin(), event.getEnd(), 0, null, null, 3, "description", "email@reference.ch", PromoCodeDiscount.CodeType.ACCESS, category.getId()); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(3); + tr.setQuantity(3); tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -466,10 +466,10 @@ private Triple testTicketsWithAccessCode() { } @Test - public void testAccessCodeLimit() { + void testAccessCodeLimit() { var triple = testTicketsWithAccessCode(); TicketReservationModification trTooMuch = new TicketReservationModification(); - trTooMuch.setAmount(1); + trTooMuch.setQuantity(1); trTooMuch.setTicketCategoryId(triple.getMiddle().getId()); TicketReservationWithOptionalCodeModification modTooMuch = new TicketReservationWithOptionalCodeModification(trTooMuch, Optional.empty()); assertThrows(TicketReservationManager.TooManyTicketsForDiscountCodeException.class, @@ -477,10 +477,10 @@ public void testAccessCodeLimit() { } @Test - public void testAccessCodeReleaseTickets() { + void testAccessCodeReleaseTickets() { var triple = testTicketsWithAccessCode(); TicketReservationModification trTooMuch = new TicketReservationModification(); - trTooMuch.setAmount(1); + trTooMuch.setQuantity(1); trTooMuch.setTicketCategoryId(triple.getMiddle().getId()); TicketReservationWithOptionalCodeModification modTooMuch = new TicketReservationWithOptionalCodeModification(trTooMuch, Optional.empty()); ticketReservationManager.cancelPendingReservation(triple.getRight(), true, null); @@ -492,7 +492,7 @@ public void testAccessCodeReleaseTickets() { } @Test - public void testWithAdditionalServices() { + void testWithAdditionalServices() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -507,7 +507,7 @@ public void testWithAdditionalServices() { TicketCategory unbounded = ticketCategoryRepository.findAllTicketCategories(event.getId()).stream().filter(t -> !t.isBounded()).findFirst().orElseThrow(IllegalStateException::new); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(3); + tr.setQuantity(3); tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -540,7 +540,7 @@ public void testWithAdditionalServices() { } @Test - public void testTicketSelectionNotEnoughTicketsAvailable() { + void testTicketSelectionNotEnoughTicketsAvailable() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -551,7 +551,7 @@ public void testTicketSelectionNotEnoughTicketsAvailable() { TicketCategory unbounded = ticketCategoryRepository.findAllTicketCategories(event.getId()).stream().filter(t -> !t.isBounded()).findFirst().orElseThrow(IllegalStateException::new); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(AVAILABLE_SEATS + 1); + tr.setQuantity(AVAILABLE_SEATS + 1); tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -559,7 +559,7 @@ public void testTicketSelectionNotEnoughTicketsAvailable() { } @Test - public void testDeletePendingPaymentUnboundedCategory() { + void testDeletePendingPaymentUnboundedCategory() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -570,7 +570,7 @@ public void testDeletePendingPaymentUnboundedCategory() { TicketCategory unbounded = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(AVAILABLE_SEATS / 2 + 1); + tr.setQuantity(AVAILABLE_SEATS / 2 + 1); tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -600,7 +600,7 @@ public void testDeletePendingPaymentUnboundedCategory() { @Test - public void testCleanupExpiredReservations() { + void testCleanupExpiredReservations() { var testCases = List.of( // 1st test case: bounded category, max 10 tickets @@ -625,7 +625,7 @@ public void testCleanupExpiredReservations() { boolean bounded = category.isBounded(); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(10); + tr.setQuantity(10); tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -663,7 +663,7 @@ public void testCleanupExpiredReservations() { } @Test - public void testCleanupOfflineExpiredReservations() { + void testCleanupOfflineExpiredReservations() { List categories = List.of( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 10, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -676,7 +676,7 @@ public void testCleanupOfflineExpiredReservations() { TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(10); + tr.setQuantity(10); tr.setTicketCategoryId(bounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); diff --git a/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java b/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java index 2eeebf9fa5..32cc71d23d 100644 --- a/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java +++ b/src/test/java/alfio/manager/WaitingQueueManagerIntegrationTest.java @@ -64,7 +64,7 @@ @ContextConfiguration(classes = {DataSourceConfiguration.class, WebSecurityConfig.class, TestConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) @Transactional -public class WaitingQueueManagerIntegrationTest extends BaseIntegrationTest { +class WaitingQueueManagerIntegrationTest extends BaseIntegrationTest { private static final Map DESCRIPTION = Collections.singletonMap("en", "desc"); @@ -94,7 +94,7 @@ public class WaitingQueueManagerIntegrationTest extends BaseIntegrationTest { private ClockProvider clockProvider; @BeforeEach - public void init() { + void init() { ensureMinimalConfiguration(configurationRepository); } @@ -103,7 +103,7 @@ private static CustomerName customerJohnDoe(Event event) { } @Test - public void testSubscribeDenied() { + void testSubscribeDenied() { List categories = getPreSalesTicketCategoryModifications(false, AVAILABLE_SEATS, true, 10); Pair pair = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository); Event event = pair.getKey(); @@ -118,7 +118,7 @@ public void testSubscribeDenied() { } @Test - public void testDistributeSeatsFirstCategoryIsUnbounded() { + void testDistributeSeatsFirstCategoryIsUnbounded() { List categories = getPreSalesTicketCategoryModifications(false, AVAILABLE_SEATS, true, 10); Pair pair = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository); Event event = pair.getKey(); @@ -134,13 +134,13 @@ public void testDistributeSeatsFirstCategoryIsUnbounded() { assertEquals("john@doe.com", subscriptionDetail.getLeft().getEmailAddress()); TicketReservationWithOptionalCodeModification reservation = subscriptionDetail.getMiddle(); assertEquals(Integer.valueOf(firstCategory.getId()), reservation.getTicketCategoryId()); - assertEquals(Integer.valueOf(1), reservation.getAmount()); + assertEquals(Integer.valueOf(1), reservation.getQuantity()); assertTrue(subscriptionDetail.getRight().isAfter(ZonedDateTime.now(clockProvider.getClock()))); } @Test - public void testDistributeSeatsFirstCategoryIsBounded() { + void testDistributeSeatsFirstCategoryIsBounded() { List categories = getPreSalesTicketCategoryModifications(true, 10, true, 10); Pair pair = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository); Event event = pair.getKey(); @@ -156,13 +156,13 @@ public void testDistributeSeatsFirstCategoryIsBounded() { assertEquals("john@doe.com", subscriptionDetail.getLeft().getEmailAddress()); TicketReservationWithOptionalCodeModification reservation = subscriptionDetail.getMiddle(); assertEquals(Integer.valueOf(firstCategory.getId()), reservation.getTicketCategoryId()); - assertEquals(Integer.valueOf(1), reservation.getAmount()); + assertEquals(Integer.valueOf(1), reservation.getQuantity()); assertTrue(subscriptionDetail.getRight().isAfter(ZonedDateTime.now(clockProvider.getClock()))); } @Test - public void testWaitingQueueForUnboundedCategory() { + void testWaitingQueueForUnboundedCategory() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(clockProvider.getClock()), LocalTime.now(clockProvider.getClock())), @@ -172,7 +172,7 @@ public void testWaitingQueueForUnboundedCategory() { TicketCategory unbounded = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(AVAILABLE_SEATS); + tr.setQuantity(AVAILABLE_SEATS); tr.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -189,7 +189,7 @@ public void testWaitingQueueForUnboundedCategory() { } @Test - public void testAssignTicketToWaitingQueueUnboundedCategory() { + void testAssignTicketToWaitingQueueUnboundedCategory() { LocalDateTime start = LocalDateTime.now(clockProvider.getClock()).minusMinutes(1); LocalDateTime end = LocalDateTime.now(clockProvider.getClock()).plusMinutes(20); List categories = Collections.singletonList( @@ -205,11 +205,11 @@ public void testAssignTicketToWaitingQueueUnboundedCategory() { TicketCategory unbounded = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(AVAILABLE_SEATS - 1); + tr.setQuantity(AVAILABLE_SEATS - 1); tr.setTicketCategoryId(unbounded.getId()); TicketReservationModification tr2 = new TicketReservationModification(); - tr2.setAmount(1); + tr2.setQuantity(1); tr2.setTicketCategoryId(unbounded.getId()); TicketReservationWithOptionalCodeModification multi = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -248,12 +248,12 @@ public void testAssignTicketToWaitingQueueUnboundedCategory() { assertEquals("john@doe.com", subscriptionDetail.getLeft().getEmailAddress()); TicketReservationWithOptionalCodeModification reservation = subscriptionDetail.getMiddle(); assertEquals(Integer.valueOf(unbounded.getId()), reservation.getTicketCategoryId()); - assertEquals(Integer.valueOf(1), reservation.getAmount()); + assertEquals(Integer.valueOf(1), reservation.getQuantity()); assertTrue(subscriptionDetail.getRight().isAfter(ZonedDateTime.now(clockProvider.getClock()))); } @Test - public void testAssignTicketToWaitingQueueBoundedCategory() { + void testAssignTicketToWaitingQueueBoundedCategory() { LocalDateTime start = LocalDateTime.now(clockProvider.getClock()).minusMinutes(2); LocalDateTime end = LocalDateTime.now(clockProvider.getClock()).plusMinutes(20); List categories = Collections.singletonList( @@ -269,11 +269,11 @@ public void testAssignTicketToWaitingQueueBoundedCategory() { TicketCategory bounded = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0); TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(AVAILABLE_SEATS - 1); + tr.setQuantity(AVAILABLE_SEATS - 1); tr.setTicketCategoryId(bounded.getId()); TicketReservationModification tr2 = new TicketReservationModification(); - tr2.setAmount(1); + tr2.setQuantity(1); tr2.setTicketCategoryId(bounded.getId()); TicketReservationWithOptionalCodeModification multi = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); @@ -310,12 +310,12 @@ public void testAssignTicketToWaitingQueueBoundedCategory() { assertEquals("john@doe.com", subscriptionDetail.getLeft().getEmailAddress()); TicketReservationWithOptionalCodeModification reservation = subscriptionDetail.getMiddle(); assertEquals(Integer.valueOf(bounded.getId()), reservation.getTicketCategoryId()); - assertEquals(Integer.valueOf(1), reservation.getAmount()); + assertEquals(Integer.valueOf(1), reservation.getQuantity()); assertTrue(subscriptionDetail.getRight().isAfter(ZonedDateTime.now(clockProvider.getClock()))); } @Test - public void testAssignTicketToWaitingQueueUnboundedCategorySelected() { + void testAssignTicketToWaitingQueueUnboundedCategorySelected() { LocalDateTime start = LocalDateTime.now(clockProvider.getClock()).minusHours(1); LocalDateTime end = LocalDateTime.now(clockProvider.getClock()).plusHours(1); @@ -338,11 +338,11 @@ public void testAssignTicketToWaitingQueueUnboundedCategorySelected() { TicketCategory second = ticketCategories.get(1); TicketReservationModification tr2 = new TicketReservationModification(); - tr2.setAmount(1); + tr2.setQuantity(1); tr2.setTicketCategoryId(second.getId()); TicketReservationModification tr3 = new TicketReservationModification(); - tr3.setAmount(1); + tr3.setQuantity(1); tr3.setTicketCategoryId(first.getId()); reserveTickets(event, first, AVAILABLE_SEATS - 2); @@ -364,20 +364,20 @@ public void testAssignTicketToWaitingQueueUnboundedCategorySelected() { assertEquals("john@doe.com", subscriptionDetail.getLeft().getEmailAddress()); TicketReservationWithOptionalCodeModification reservation = subscriptionDetail.getMiddle(); assertEquals(Integer.valueOf(first.getId()), reservation.getTicketCategoryId()); - assertEquals(Integer.valueOf(1), reservation.getAmount()); + assertEquals(Integer.valueOf(1), reservation.getQuantity()); assertTrue(subscriptionDetail.getRight().isAfter(ZonedDateTime.now(clockProvider.getClock()))); subscriptionDetail = subscriptions.get(1); assertEquals("john@doe2.com", subscriptionDetail.getLeft().getEmailAddress()); reservation = subscriptionDetail.getMiddle(); assertEquals(Integer.valueOf(second.getId()), reservation.getTicketCategoryId()); - assertEquals(Integer.valueOf(1), reservation.getAmount()); + assertEquals(Integer.valueOf(1), reservation.getQuantity()); assertTrue(subscriptionDetail.getRight().isAfter(ZonedDateTime.now(clockProvider.getClock()))); } private String reserveTickets(Event event, TicketCategory category, int num) { TicketReservationModification tr = new TicketReservationModification(); - tr.setAmount(num); + tr.setQuantity(num); tr.setTicketCategoryId(category.getId()); TicketReservationWithOptionalCodeModification tcm = new TicketReservationWithOptionalCodeModification(tr, Optional.empty()); String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(tcm), Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); @@ -393,7 +393,7 @@ private String reserveTickets(Event event, TicketCategory category, int num) { } @Test - public void testNoPublicCategoryAvailable() { + void testNoPublicCategoryAvailable() { LocalDateTime start = LocalDateTime.now(clockProvider.getClock()).minusHours(1); LocalDateTime end = LocalDateTime.now(clockProvider.getClock()).plusHours(1); @@ -428,7 +428,7 @@ public void testNoPublicCategoryAvailable() { } @Test - public void testTicketBelongsToExpiredCategory() { + void testTicketBelongsToExpiredCategory() { LocalDateTime start = LocalDateTime.now(clockProvider.getClock()).minusHours(1); LocalDateTime end = LocalDateTime.now(clockProvider.getClock()).plusHours(1); diff --git a/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java b/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java index c00f12f54e..c26f8de9b2 100644 --- a/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java +++ b/src/test/java/alfio/manager/system/DataMigratorIntegrationTest.java @@ -60,7 +60,7 @@ @SpringBootTest @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class}) @ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) -public class DataMigratorIntegrationTest extends BaseIntegrationTest { +class DataMigratorIntegrationTest extends BaseIntegrationTest { private static final int AVAILABLE_SEATS = 20; private static final Map DESCRIPTION = Collections.singletonMap("en", "desc"); @@ -118,7 +118,7 @@ private Pair initEvent(List categories } @Test - public void testMigration() { + void testMigration() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -147,7 +147,7 @@ public void testMigration() { } @Test - public void testMigrationWithExistingRecord() { + void testMigrationWithExistingRecord() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -176,7 +176,7 @@ public void testMigrationWithExistingRecord() { } @Test - public void testAlreadyMigratedEvent() { + void testAlreadyMigratedEvent() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -206,7 +206,7 @@ public void testAlreadyMigratedEvent() { } @Test - public void testUpdateDisplayName() { + void testUpdateDisplayName() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -232,7 +232,7 @@ public void testUpdateDisplayName() { } @Test - public void testUpdateTicketReservation() { + void testUpdateTicketReservation() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -242,7 +242,7 @@ public void testUpdateTicketReservation() { Event event = eventUsername.getKey(); try { TicketReservationModification trm = new TicketReservationModification(); - trm.setAmount(1); + trm.setQuantity(1); trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId()); TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); Date expiration = DateUtils.addDays(new Date(), 1); @@ -256,7 +256,7 @@ public void testUpdateTicketReservation() { } @Test - public void testFixCategoriesSize() { + void testFixCategoriesSize() { List categories = Arrays.asList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS -1, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -279,7 +279,7 @@ public void testFixCategoriesSize() { } @Test - public void testFixStuckTickets() { + void testFixStuckTickets() { List categories = Collections.singletonList( new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(ClockProvider.clock()), LocalTime.now(ClockProvider.clock())), @@ -288,7 +288,7 @@ public void testFixStuckTickets() { Pair eventUsername = initEvent(categories); Event event = eventUsername.getKey(); TicketReservationModification trm = new TicketReservationModification(); - trm.setAmount(1); + trm.setQuantity(1); trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId()); TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm, Optional.empty()); Date expiration = DateUtils.addDays(new Date(), 1); From 0fc91679148d299e3b643dd609884cf0696978f0 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Mon, 31 Jan 2022 19:12:40 +0100 Subject: [PATCH 005/218] update errorprone --- build.gradle | 9 ++++++--- src/main/java/alfio/manager/UploadedResourceManager.java | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 61220660a5..20ed0c6188 100644 --- a/build.gradle +++ b/build.gradle @@ -217,7 +217,7 @@ dependencies { testImplementation 'org.seleniumhq.selenium:selenium-java:4.1.1' - errorprone('com.google.errorprone:error_prone_core:2.4.0') + errorprone('com.google.errorprone:error_prone_core:2.10.0') } // -- license configuration @@ -292,7 +292,8 @@ compileTestJava { 'AlmostJavadoc', 'MissingSummary', 'EscapedEntity', - 'EmptyBlockTag' + 'EmptyBlockTag', + 'SameNameButDifferent' ) } @@ -307,7 +308,9 @@ compileJava { 'AlmostJavadoc', 'MissingSummary', 'EscapedEntity', - 'EmptyBlockTag' + 'EmptyBlockTag', + 'SameNameButDifferent', + 'ReturnValueIgnored' ) } diff --git a/src/main/java/alfio/manager/UploadedResourceManager.java b/src/main/java/alfio/manager/UploadedResourceManager.java index c31b936979..df2796e7fb 100644 --- a/src/main/java/alfio/manager/UploadedResourceManager.java +++ b/src/main/java/alfio/manager/UploadedResourceManager.java @@ -93,7 +93,7 @@ public Optional saveResource(UploadBase64FileModification file) { uploadedResourceRepository.delete(file.getName()); } - return Optional.ofNullable(uploadedResourceRepository.upload(null, null, file, getAttributes(file))); + return Optional.of(uploadedResourceRepository.upload(null, null, file, getAttributes(file))); } public Optional saveResource(int organizationId, UploadBase64FileModification file) { @@ -101,7 +101,7 @@ public Optional saveResource(int organizationId, UploadBase64FileModifi uploadedResourceRepository.delete(organizationId, file.getName()); } - return Optional.ofNullable(uploadedResourceRepository.upload(organizationId, null, file, getAttributes(file))); + return Optional.of(uploadedResourceRepository.upload(organizationId, null, file, getAttributes(file))); } public Optional saveResource(int organizationId, int eventId, UploadBase64FileModification file) { From c1937536dff6d4143f42e1e6df48eda850a69ba2 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Mon, 31 Jan 2022 20:31:24 +0100 Subject: [PATCH 006/218] update sourceCompatibility to 17 --- .github/workflows/build-on-push.yml | 8 ++++---- README.md | 6 +++--- build.gradle | 5 ++--- gradle.properties | 4 ++-- src/main/dist/Dockerfile | 8 ++++---- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build-on-push.yml b/.github/workflows/build-on-push.yml index 9720316dd2..ee4d5a8ec8 100644 --- a/.github/workflows/build-on-push.yml +++ b/.github/workflows/build-on-push.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - postgresql: ['9.6','14'] + postgresql: ['10','14'] services: postgres: image: postgres:${{ matrix.postgresql }} @@ -33,10 +33,10 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradlew') }} restore-keys: | ${{ runner.os }}-gradlew- - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 17 - name: Set up DB run: | sudo apt-get install --yes postgresql-client @@ -58,7 +58,7 @@ jobs: # env: # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - name: 'Upload Build' - if: ${{ github.repository == 'alfio-event/alf.io' && matrix.postgresql == '9.6'}} + if: ${{ github.repository == 'alfio-event/alf.io' && matrix.postgresql == '10'}} uses: actions/upload-artifact@v2 with: name: dist diff --git a/README.md b/README.md index 0d7717491d..b357407eb8 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ If you want to build and deploy alf.io by yourself, we strongly suggest you to u ## Prerequisites -You should have installed Java version **11** (e.g. [Oracle's](http://www.oracle.com/technetwork/java/javase/downloads/index.html), [OpenJDK](http://openjdk.java.net/install/), or any other distribution) to build and run alf.io. Please note that for the build process the JDK is required. +You should have installed Java version **17** (e.g. [Oracle's](http://www.oracle.com/technetwork/java/javase/downloads/index.html), [OpenJDK](http://openjdk.java.net/install/), or any other distribution) to build and run alf.io. Please note that for the build process the JDK is required. -Postgresql version 9.6 or later. +Postgresql version 10 or later. Additionally, the database user that creates and uses the tables should not be a "SUPERUSER", or else the row security policy checks will not be applied. @@ -46,7 +46,7 @@ You must specify a project property at the command line, such as ``` The local "bootRun" task has the following prerequisites: -- a PostgreSQL (version 9.6 or later) instance up and running on localhost:5432 +- a PostgreSQL (version 10 or later) instance up and running on localhost:5432 - a _postgres_ user having a password: _password_ - a database named _alfio_ diff --git a/build.gradle b/build.gradle index 20ed0c6188..0ef3599ce5 100644 --- a/build.gradle +++ b/build.gradle @@ -56,8 +56,8 @@ apply plugin: 'project-report' task validate { //check JDK version def javaVersion = JavaVersion.current() - if (!javaVersion.isJava11Compatible()) { - throw new GradleException("A Java JDK 11+ is required to build the project.") + if (!javaVersion.isCompatibleWith(JavaVersion.VERSION_17)) { + throw new GradleException("A Java JDK 17+ is required to build the project.") } } @@ -321,7 +321,6 @@ test { useJUnitPlatform() systemProperties = System.properties systemProperties.remove("java.endorsed.dirs") - jvmArgs("--illegal-access=warn") testLogging { events "failed" exceptionFormat "full" diff --git a/gradle.properties b/gradle.properties index 29e7944834..9276ed207e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,8 +2,8 @@ group=alfio version=2.0-M5-SNAPSHOT -sourceCompatibility=11 -targetCompatibility=11 +sourceCompatibility=17 +targetCompatibility=17 systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" diff --git a/src/main/dist/Dockerfile b/src/main/dist/Dockerfile index f8713c944f..31b995f6e2 100644 --- a/src/main/dist/Dockerfile +++ b/src/main/dist/Dockerfile @@ -5,18 +5,18 @@ # - https://august.nagro.us/small-java.html # -FROM azul/zulu-openjdk-alpine:15.0.2 as zulu +FROM azul/zulu-openjdk-alpine:17 as zulu RUN $JAVA_HOME/bin/jlink --compress=1 --strip-java-debug-attributes --no-header-files --no-man-pages \ --module-path $JAVA_HOME/jmods \ - # see https://github.com/ben-manes/caffeine/issues/273 + # see https://github.com/ben-manes/caffeine/issues/273 TODO investigate if we can remove jdk.unsupported # see https://docs.oracle.com/en/java/javase/11/security/oracle-providers.html#GUID-9224B90B-7B2F-41F9-BB96-C0A1B6A0FEAA --add-modules java.desktop,java.logging,java.sql,java.management,java.naming,jdk.unsupported,jdk.crypto.ec,java.net.http,jdk.localedata \ --include-locales en,it,es,nl,fr,de,ro,pt,tr,pl,da,bg,sv \ --output /jlinked -FROM alpine:3.12 -LABEL org.opencontainers.image.source https://github.com/alfio-event/alf.io +FROM alpine:3.15 +LABEL org.opencontainers.image.source=https://github.com/alfio-event/alf.io COPY --from=zulu /jlinked /opt/jdk/ From da5e4e61d5a48b49b446d83ca02c1088c2bfa5eb Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Mon, 31 Jan 2022 20:34:47 +0100 Subject: [PATCH 007/218] fix workflows --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/e2e-test.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0e0dee3c6c..bb0c65f875 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,10 +31,10 @@ jobs: # with: # languages: go, javascript, csharp, python, cpp, java - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 17 - name: Build with Gradle run: ./gradlew build -x test diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 5ed4d1caf0..f8384ce19f 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -25,10 +25,10 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradlew') }} restore-keys: | ${{ runner.os }}-gradlew- - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 17 - name: 'BrowserStack Env Setup' uses: 'browserstack/github-actions/setup-env@master' with: From c4c4b1b3d9934967a7fffa98bff7dbd18cfa1e52 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 5 Feb 2022 17:43:50 +0100 Subject: [PATCH 008/218] revert removal of getter/setter in TicketReservationModification --- .../modification/TicketReservationModification.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/alfio/model/modification/TicketReservationModification.java b/src/main/java/alfio/model/modification/TicketReservationModification.java index 9688f8a6d9..ff2afdf08e 100644 --- a/src/main/java/alfio/model/modification/TicketReservationModification.java +++ b/src/main/java/alfio/model/modification/TicketReservationModification.java @@ -28,4 +28,14 @@ public class TicketReservationModification implements Serializable { private Integer quantity; private List> metadata; + // temporary until we replace the public front-end + @Deprecated(forRemoval = true) + public Integer getAmount() { + return quantity; + } + + @Deprecated(forRemoval = true) + public void setAmount(Integer amount) { + this.quantity = amount; + } } From 96130f43d469538f772bfb55335b953f7ad7a22a Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Fri, 11 Mar 2022 09:22:09 +0100 Subject: [PATCH 009/218] add system-wide banner message --- gradle.properties | 2 +- src/main/java/alfio/controller/api/v2/model/AlfioInfo.java | 1 + .../java/alfio/manager/system/ConfigurationManager.java | 6 ++++-- src/main/java/alfio/model/system/ConfigurationKeys.java | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9276ed207e..aafcdbe8f4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,4 +8,4 @@ targetCompatibility=17 systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" # https://jitpack.io/#alfio-event/alf.io-public-frontend -> go to commit tab, set the version -alfioPublicFrontendVersion=908c55db5a \ No newline at end of file +alfioPublicFrontendVersion=0267c8c7cb \ No newline at end of file diff --git a/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java b/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java index 6524e7c273..165384e725 100644 --- a/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java @@ -31,4 +31,5 @@ public class AlfioInfo { private final String globalPrivacyPolicyUrl; private final String globalTermsUrl; private final InvoicingConfiguration invoicingConfiguration; + private final String announcementBannerContentHTML; } diff --git a/src/main/java/alfio/manager/system/ConfigurationManager.java b/src/main/java/alfio/manager/system/ConfigurationManager.java index f9574a2384..83dc156b8e 100644 --- a/src/main/java/alfio/manager/system/ConfigurationManager.java +++ b/src/main/java/alfio/manager/system/ConfigurationManager.java @@ -689,7 +689,8 @@ public AlfioInfo getInfo(HttpSession session) { ENABLE_EU_VAT_DIRECTIVE, COUNTRY_OF_BUSINESS, ENABLE_REVERSE_CHARGE_IN_PERSON, - ENABLE_REVERSE_CHARGE_ONLINE); + ENABLE_REVERSE_CHARGE_ONLINE, + ANNOUNCEMENT_BANNER_CONTENT); var conf = getFor(options, ConfigurationLevel.system()); var analyticsConf = AnalyticsConfiguration.build(conf, session); @@ -700,7 +701,8 @@ public AlfioInfo getInfo(HttpSession session) { analyticsConf, conf.get(GLOBAL_PRIVACY_POLICY).getValueOrNull(), conf.get(GLOBAL_TERMS).getValueOrNull(), - PurchaseContextInfoBuilder.invoicingInfo(this, conf)); + PurchaseContextInfoBuilder.invoicingInfo(this, conf), + StringUtils.trimToNull(conf.get(ANNOUNCEMENT_BANNER_CONTENT).getValueOrNull())); } public Map getPublicOpenIdConfiguration() { diff --git a/src/main/java/alfio/model/system/ConfigurationKeys.java b/src/main/java/alfio/model/system/ConfigurationKeys.java index 9327b1c0b3..e516997ec8 100644 --- a/src/main/java/alfio/model/system/ConfigurationKeys.java +++ b/src/main/java/alfio/model/system/ConfigurationKeys.java @@ -42,6 +42,7 @@ public enum ConfigurationKeys { BASE_URL("Base application url", false, SettingCategory.GENERAL, ComponentType.TEXT, true, EnumSet.of(SYSTEM)), GLOBAL_PRIVACY_POLICY("Global Privacy Policy URL (to be displayed on the event list)", false, SettingCategory.GENERAL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), GLOBAL_TERMS("Global Terms And Conditions (to be displayed on the event list)", false, SettingCategory.GENERAL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), + ANNOUNCEMENT_BANNER_CONTENT("Announcement banner content", false, SettingCategory.GENERAL, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM)), MAPS_PROVIDER("Select the maps provider (None, Google, Here)", false, SettingCategory.MAP, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), MAPS_CLIENT_API_KEY("Google maps' client api key", false, SettingCategory.MAP, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), From a7add77606881c1c05452e018ca588c18f687f45 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Fri, 11 Mar 2022 11:29:01 +0100 Subject: [PATCH 010/218] update frontend version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index aafcdbe8f4..6b9b3bf7fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,4 +8,4 @@ targetCompatibility=17 systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" # https://jitpack.io/#alfio-event/alf.io-public-frontend -> go to commit tab, set the version -alfioPublicFrontendVersion=0267c8c7cb \ No newline at end of file +alfioPublicFrontendVersion=e2f0da47a0 \ No newline at end of file From 4cbbf9fc5c688623fc2d983c3620ee68d8ade25a Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Fri, 11 Mar 2022 14:16:22 +0100 Subject: [PATCH 011/218] CSP: add hash for inline script used by angular 'css optimization' --- src/main/java/alfio/controller/IndexController.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/alfio/controller/IndexController.java b/src/main/java/alfio/controller/IndexController.java index 0d90c44da3..5c798521ea 100644 --- a/src/main/java/alfio/controller/IndexController.java +++ b/src/main/java/alfio/controller/IndexController.java @@ -495,7 +495,9 @@ public String addCspHeader(HttpServletResponse response, ConfigurationLevel conf } response.addHeader("Content-Security-Policy", "object-src 'none'; "+ - "script-src 'strict-dynamic' 'nonce-" + nonce + "' 'unsafe-inline' http: https:; " + + "script-src 'strict-dynamic' 'nonce-" + nonce + "' 'unsafe-inline' http: https: " + + "'unsafe-hashes' 'sha256-MhtPZXr7+LpJUY5qtMutB+qWfQtMaPccfe7QXtCcEYc='" // see https://github.com/angular/angular-cli/issues/20864#issuecomment-983672336 + +"; " + "base-uri 'self'; " + "frame-ancestors " + frameAncestors + "; " + reportUri); From 82d2a26bc85834b0815a6f60d192c26a355f93a9 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Fri, 11 Mar 2022 15:15:59 +0100 Subject: [PATCH 012/218] a11y: add custom amount label --- src/main/resources/alfio/i18n/public.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/alfio/i18n/public.properties b/src/main/resources/alfio/i18n/public.properties index e80240443e..02146896b4 100644 --- a/src/main/resources/alfio/i18n/public.properties +++ b/src/main/resources/alfio/i18n/public.properties @@ -37,6 +37,7 @@ show-subscription.sold-out.message=We''re sorry but currently we don''t have any show-subscription.header.title=Buy a {0} subscription show-event.tickets.left={0} left show-event.category.quantity=Quantity +show-event.additional.custom-amount=Amount show-event.by=By show-event.tickets=Tickets show-event.additional-services=Additional options From bb52c7cbf99107b76354779dde98c9a47755db1e Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Fri, 11 Mar 2022 15:25:35 +0100 Subject: [PATCH 013/218] update italian translation --- src/main/resources/alfio/i18n/public_it.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/alfio/i18n/public_it.properties b/src/main/resources/alfio/i18n/public_it.properties index 68ba8e7f9b..3e620c9e95 100644 --- a/src/main/resources/alfio/i18n/public_it.properties +++ b/src/main/resources/alfio/i18n/public_it.properties @@ -443,6 +443,7 @@ server-error = Si è verificato un errore inatteso. Per favore segnala quanto ac session-expired.header.title = Sessione scaduta show-event.add-to-calendar = Aggiungi al calendario show-event.additional-services = Opzioni aggiuntive +show-event.additional.custom-amount = Importo # show-event.ms show-event.by = Organizzato da show-event.category.quantity = Quantità From 14c1792dec78a810f112554b94d626d84e11c411 Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Fri, 11 Mar 2022 16:52:01 +0100 Subject: [PATCH 014/218] a11y: signal that link opens in a new tab --- .../api/v2/user/EventApiV2Controller.java | 4 +-- .../api/v2/user/support/EventLoader.java | 2 +- .../alfio/controller/support/Formatters.java | 14 +++++++---- .../java/alfio/util/MustacheCustomTag.java | 20 ++++++++++++--- .../resources/alfio/i18n/public.properties | 3 ++- .../controller/support/FormattersTest.java | 25 +++++++++++++++++++ 6 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 9b1f018593..01e1f4e2cb 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -184,7 +184,7 @@ public ResponseEntity getTicketCategories(@PathVariable("eventN boolean displayTicketsLeft = configurations.get(DISPLAY_TICKETS_LEFT_INDICATOR).getValueAsBooleanOrDefault(); var categoriesByExpiredFlag = saleableTicketCategories.stream() .map(stc -> { - var description = Formatters.applyCommonMark(ticketCategoryDescriptions.getOrDefault(stc.getId(), Collections.emptyMap())); + var description = Formatters.applyCommonMark(ticketCategoryDescriptions.getOrDefault(stc.getId(), Collections.emptyMap()), messageSource); var expiration = Formatters.getFormattedDate(event, stc.getZonedExpiration(), "common.ticket-category.date-format", messageSource); var inception = Formatters.getFormattedDate(event, stc.getZonedInception(), "common.ticket-category.date-format", messageSource); return new TicketCategory(stc, description, inception, expiration, displayTicketsLeft && !stc.isAccessRestricted()); @@ -213,7 +213,7 @@ public ResponseEntity getTicketCategories(@PathVariable("eventN var expiration = Formatters.getFormattedDate(event, as.getZonedExpiration(), "common.ticket-category.date-format", messageSource); var inception = Formatters.getFormattedDate(event, as.getZonedInception(), "common.ticket-category.date-format", messageSource); var title = additionalServiceTexts.getOrDefault(as.getId(), Collections.emptyMap()).getOrDefault(AdditionalServiceText.TextType.TITLE, Collections.emptyMap()); - var description = Formatters.applyCommonMark(additionalServiceTexts.getOrDefault(as.getId(), Collections.emptyMap()).getOrDefault(AdditionalServiceText.TextType.DESCRIPTION, Collections.emptyMap())); + var description = Formatters.applyCommonMark(additionalServiceTexts.getOrDefault(as.getId(), Collections.emptyMap()).getOrDefault(AdditionalServiceText.TextType.DESCRIPTION, Collections.emptyMap()), messageSource); return new AdditionalService(as.getId(), as.getType(), as.getSupplementPolicy(), as.isFixPrice(), as.getAvailableQuantity(), as.getMaxQtyPerOrder(), as.getFree(), as.getFormattedFinalPrice(), as.getSupportsDiscount(), as.getDiscountedPrice(), as.getVatApplies(), as.getVatIncluded(), as.getVatPercentage().toString(), diff --git a/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java b/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java index 5fc2e85b9c..3a5d6888df 100644 --- a/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java +++ b/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java @@ -56,7 +56,7 @@ public Optional loadEventInfo(String eventName, HttpSes var messageSource = messageSourceAndOverride.getLeft(); var i18nOverride = messageSourceAndOverride.getRight(); - var descriptions = Formatters.applyCommonMark(eventDescriptionRepository.findDescriptionByEventIdAsMap(event.getId())); + var descriptions = Formatters.applyCommonMark(eventDescriptionRepository.findDescriptionByEventIdAsMap(event.getId()), messageSource); var organization = organizationRepository.getContactById(event.getOrganizationId()); diff --git a/src/main/java/alfio/controller/support/Formatters.java b/src/main/java/alfio/controller/support/Formatters.java index a620236884..e4f70f8c1f 100644 --- a/src/main/java/alfio/controller/support/Formatters.java +++ b/src/main/java/alfio/controller/support/Formatters.java @@ -26,16 +26,15 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.BiConsumer; @UtilityClass @Log4j2 public class Formatters { + public static final String LINK_NEW_TAB_KEY = "link.new-tab"; + public static Map getFormattedDate(LocalizedContent localizedContent, ZonedDateTime date, String code, MessageSource messageSource) { if(localizedContent != null && date != null) { return getFormattedDate(localizedContent.getContentLanguages(), date, code, messageSource); @@ -79,13 +78,18 @@ public static FormattedEventDates getFormattedDates(Event e, MessageSource messa } public static Map applyCommonMark(Map in) { + return applyCommonMark(in, null); + } + + public static Map applyCommonMark(Map in, MessageSource messageSource) { if (in == null) { return Collections.emptyMap(); } var res = new HashMap(); in.forEach((k, v) -> { - res.put(k, MustacheCustomTag.renderToHtmlCommonmarkEscaped(v)); + var targetBlankMessage = messageSource != null ? messageSource.getMessage(LINK_NEW_TAB_KEY, null, Locale.forLanguageTag(k)) : null; + res.put(k, MustacheCustomTag.renderToHtmlCommonmarkEscaped(v, targetBlankMessage)); }); return res; } diff --git a/src/main/java/alfio/util/MustacheCustomTag.java b/src/main/java/alfio/util/MustacheCustomTag.java index 063484030d..79d057f9f4 100644 --- a/src/main/java/alfio/util/MustacheCustomTag.java +++ b/src/main/java/alfio/util/MustacheCustomTag.java @@ -26,6 +26,7 @@ import org.commonmark.ext.gfm.tables.TablesExtension; import org.commonmark.node.Link; import org.commonmark.node.Node; +import org.commonmark.node.Text; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.AttributeProvider; import org.commonmark.renderer.html.HtmlRenderer; @@ -140,6 +141,7 @@ private static Pair> parseParams(String r) { private static final Parser COMMONMARK_PARSER = Parser.builder().extensions(COMMONMARK_EXTENSIONS).build(); private static final HtmlRenderer COMMONMARK_RENDERER = HtmlRenderer.builder().extensions(COMMONMARK_EXTENSIONS).attributeProviderFactory((ctx) -> new TargetBlankProvider()).build(); private static final TextContentRenderer COMMONMARK_TEXT_RENDERER = TextContentRenderer.builder().extensions(COMMONMARK_EXTENSIONS).build(); + private static final ThreadLocal A11Y_NEW_TAB_LABEL = new ThreadLocal<>(); //Open in a new window if the link contains an absolute url private static class TargetBlankProvider implements AttributeProvider { @@ -151,14 +153,26 @@ public void setAttributes(Node node, String tagName, Map attribu if (UrlUtils.isAbsoluteUrl(destination)) { attributes.put("target", "_blank"); attributes.put("rel", "nofollow noopener noreferrer"); + var newTabLabel = A11Y_NEW_TAB_LABEL.get(); + if (newTabLabel != null) { + attributes.put("aria-label", ((Text)node.getFirstChild()).getLiteral() + " " + newTabLabel); + } } } } } - public static String renderToHtmlCommonmarkEscaped(String input) { - Node document = COMMONMARK_PARSER.parse(StringEscapeUtils.escapeHtml4(input)); - return COMMONMARK_RENDERER.render(document); + return renderToHtmlCommonmarkEscaped(input, null); + } + + public static String renderToHtmlCommonmarkEscaped(String input, String localizedNewWindowLabel) { + try { + A11Y_NEW_TAB_LABEL.set(localizedNewWindowLabel); + Node document = COMMONMARK_PARSER.parse(StringEscapeUtils.escapeHtml4(input)); + return COMMONMARK_RENDERER.render(document); + } finally { + A11Y_NEW_TAB_LABEL.remove(); + } } public static String renderToTextCommonmark(String input) { diff --git a/src/main/resources/alfio/i18n/public.properties b/src/main/resources/alfio/i18n/public.properties index 02146896b4..f980714b70 100644 --- a/src/main/resources/alfio/i18n/public.properties +++ b/src/main/resources/alfio/i18n/public.properties @@ -597,4 +597,5 @@ time.extended.pattern=HH:mm online.check-in.waiting-room.button=Try again online.check-in.waiting-room.event-started=The event has started but we could not let you in. online.check-in.waiting-room.event-started.contact-organizers=Please try again by clicking on the button below or contact the organizers. -online.check-in.waiting-room.event-ended=Sorry, this event has ended. \ No newline at end of file +online.check-in.waiting-room.event-ended=Sorry, this event has ended. +link.new-tab=Opens in a new tab \ No newline at end of file diff --git a/src/test/java/alfio/controller/support/FormattersTest.java b/src/test/java/alfio/controller/support/FormattersTest.java index 402ffae629..bedcb98423 100644 --- a/src/test/java/alfio/controller/support/FormattersTest.java +++ b/src/test/java/alfio/controller/support/FormattersTest.java @@ -24,6 +24,10 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; /** * This test checks if all the date patterns for all defined languages are correct, in order to spot errors at build @@ -46,4 +50,25 @@ void getFormattedDates() { FORMATTER_CODES.forEach(code -> Formatters.formatDateForLocale(now, code, messageSource, (a, b) -> Assertions.assertNotNull(b), cl, true)) ); } + + @Test + void getFormattedLink() { + var messageSource = new ResourceBundleMessageSource(); + messageSource.setBasename("alfio.i18n.public"); + var rendered = Formatters.applyCommonMark(Map.of("en", "[link](https://alf.io)")); + assertFalse(rendered.isEmpty()); + assertEquals(1, rendered.size()); + assertEquals("

link

", rendered.get("en").trim()); + } + + @Test + void getFormattedLinkWithAriaLabel() { + var messageSource = new ResourceBundleMessageSource(); + messageSource.setBasename("alfio.i18n.public"); + var message = messageSource.getMessage(Formatters.LINK_NEW_TAB_KEY, null, Locale.ENGLISH); + var rendered = Formatters.applyCommonMark(Map.of("en", "[link](https://alf.io)"), messageSource); + assertFalse(rendered.isEmpty()); + assertEquals(1, rendered.size()); + assertEquals("

link

", rendered.get("en").trim()); + } } \ No newline at end of file From c2b5165fd3d05ad5a945b106e9ac8fd5db14b58b Mon Sep 17 00:00:00 2001 From: Celestino Bellone Date: Fri, 11 Mar 2022 17:00:35 +0100 Subject: [PATCH 015/218] a11y: signal that link opens in a new tab --- src/main/resources/alfio/i18n/public.properties | 2 +- src/main/resources/alfio/i18n/public_it.properties | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/alfio/i18n/public.properties b/src/main/resources/alfio/i18n/public.properties index f980714b70..60d375dd51 100644 --- a/src/main/resources/alfio/i18n/public.properties +++ b/src/main/resources/alfio/i18n/public.properties @@ -598,4 +598,4 @@ online.check-in.waiting-room.button=Try again online.check-in.waiting-room.event-started=The event has started but we could not let you in. online.check-in.waiting-room.event-started.contact-organizers=Please try again by clicking on the button below or contact the organizers. online.check-in.waiting-room.event-ended=Sorry, this event has ended. -link.new-tab=Opens in a new tab \ No newline at end of file +link.new-tab=(Opens in a new tab) \ No newline at end of file diff --git a/src/main/resources/alfio/i18n/public_it.properties b/src/main/resources/alfio/i18n/public_it.properties index 3e620c9e95..47f946c4df 100644 --- a/src/main/resources/alfio/i18n/public_it.properties +++ b/src/main/resources/alfio/i18n/public_it.properties @@ -202,6 +202,7 @@ invoice.vat-invoice = Fattura # please do not translate. This is strictly related to the Italian market invoice.vat-not-added = {0} non inclusa come da direttiva sulla Scissione dei Pagamenti invoice.vat-voided = {0} omessa, come da direttive UE +link.new-tab = (si apre in un nuovo tab) locale = it my-orders.confirmation-date = Data di conferma my-orders.description = Qui puoi trovare la lista delle tue prenotazioni From 316dd8fd4bae55f1aef73609139d78d57f4e9078 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sun, 13 Mar 2022 07:54:35 +0100 Subject: [PATCH 016/218] add pdf ua support (#1057) * enable accessibility for pdf ticket * add metadata for credit-note/invoice/receipt --- .../alfio/controller/support/TemplateProcessor.java | 2 ++ src/main/resources/alfio/i18n/public.properties | 3 ++- src/main/resources/alfio/templates/credit-note.ms | 8 ++++++-- src/main/resources/alfio/templates/invoice.ms | 8 ++++++-- src/main/resources/alfio/templates/receipt.ms | 8 ++++++-- src/main/resources/alfio/templates/ticket.ms | 10 +++++++--- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/main/java/alfio/controller/support/TemplateProcessor.java b/src/main/java/alfio/controller/support/TemplateProcessor.java index 795584b917..98a8ee569f 100644 --- a/src/main/java/alfio/controller/support/TemplateProcessor.java +++ b/src/main/java/alfio/controller/support/TemplateProcessor.java @@ -113,6 +113,8 @@ public static void renderToPdf(String page, OutputStream os, ExtensionManager ex builder.useProtocolsStreamImplementation(new AlfioInternalFSStreamFactory(), "alfio-internal"); builder.useProtocolsStreamImplementation(new InvalidProtocolFSStreamFactory(), "http", "https", "file", "jar"); builder.useFastMode(); + builder.usePdfUaAccessbility(true); + builder.usePdfAConformance(PdfRendererBuilder.PdfAConformance.PDFA_3_U); var parser = new Parser(); diff --git a/src/main/resources/alfio/i18n/public.properties b/src/main/resources/alfio/i18n/public.properties index 60d375dd51..d462cfb9a9 100644 --- a/src/main/resources/alfio/i18n/public.properties +++ b/src/main/resources/alfio/i18n/public.properties @@ -598,4 +598,5 @@ online.check-in.waiting-room.button=Try again online.check-in.waiting-room.event-started=The event has started but we could not let you in. online.check-in.waiting-room.event-started.contact-organizers=Please try again by clicking on the button below or contact the organizers. online.check-in.waiting-room.event-ended=Sorry, this event has ended. -link.new-tab=(Opens in a new tab) \ No newline at end of file +qr.code=QR Code +link.new-tab=(Opens in a new tab) diff --git a/src/main/resources/alfio/templates/credit-note.ms b/src/main/resources/alfio/templates/credit-note.ms index 16d4827423..63d80ebc7c 100644 --- a/src/main/resources/alfio/templates/credit-note.ms +++ b/src/main/resources/alfio/templates/credit-note.ms @@ -1,6 +1,10 @@ - + + {{#i18n}}invoice.credit-note{{/i18n}} + + + + + + + + {{#logo}} + + {{/logo}} + + +

{{title}}

+ +

{{#i18n}}reservation-page-complete.subscription{{/i18n}}

+ + + + + +
{{#i18n}}reservation-page-complete.subscription.owner{{/i18n}}:{{subscription.firstName}} {{subscription.lastName}} <{{subscription.email}}>
+

{{#subscriptionDescription}}{{/subscriptionDescription}}

+ +

{{#i18n}}reservation-page-complete.subscription.pin-description{{/i18n}}

+

{{subscription.pin}}

+ +

{{#i18n}}reservation-page-complete.subscription.id-description{{/i18n}}

+

{{subscription.id}}

+ +

+ + + + + + +
{{#i18n}}ticket.order-information{{/i18n}}{{#i18n}}ticket.order-information-values [{{reservationId}}] [{{reservation.fullName}}]{{/i18n}}
+ + \ No newline at end of file diff --git a/src/main/resources/alfio/templates/ticket.ms b/src/main/resources/alfio/templates/ticket.ms index e85fc1b03e..ddec71f930 100644 --- a/src/main/resources/alfio/templates/ticket.ms +++ b/src/main/resources/alfio/templates/ticket.ms @@ -88,6 +88,12 @@ {{#i18n}}ticket.reference-number{{/i18n}} {{ticket.uuid}} + {{#hasSubscription}} + + {{#i18n}}reservation-page.subscription{{/i18n}} + {{subscriptionTitle}} + + {{/hasSubscription}} {{#i18n}}ticket.order-information{{/i18n}} {{#i18n}}ticket.order-information-values [{{reservationId}}] [{{reservation.fullName}}]{{/i18n}} diff --git a/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java b/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java index 2479a8bf49..4ac134d20e 100644 --- a/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java +++ b/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java @@ -129,7 +129,8 @@ void createSingleTicketWithMetadata() { new ReservationConfiguration(true), null, null, - "en" + "en", + null ); var principal = new APITokenAuthentication(username, null, List.of()); var response = controller.createTicketsReservation(event.getShortName(), creationRequest, principal); @@ -167,7 +168,8 @@ void createTwoTicketsWithMetadata() { null, null, null, - "en" + "en", + null ); var principal = new APITokenAuthentication(username, null, List.of()); var response = controller.createTicketsReservation(event.getShortName(), creationRequest, principal); @@ -216,7 +218,8 @@ void createSingleTicketWithAuthenticatedUser() { null, user, null, - "en" + "en", + null ); var principal = new APITokenAuthentication(username, null, List.of()); var response = controller.createTicketsReservation(event.getShortName(), creationRequest, principal); @@ -267,7 +270,8 @@ void createSingleTicketWithAttendees() { null, user, null, - "en" + "en", + null ); var principal = new APITokenAuthentication(username, null, List.of()); var response = controller.createTicketsReservation(event.getShortName(), creationRequest, principal); @@ -319,7 +323,8 @@ void createMultipleTicketsWithAttendees() { null, user, null, - "en" + "en", + null ); var principal = new APITokenAuthentication(username, null, List.of()); var response = controller.createTicketsReservation(event.getShortName(), creationRequest, principal); @@ -350,6 +355,59 @@ void createMultipleTicketsWithAttendees() { assertFalse(createdUser.isPresent()); } + @Test + void createSingleTicketWithSubscriptionId() { + var subscriptionId = UUID.randomUUID().toString(); + var category = ticketCategoryRepository.findFirstWithAvailableTickets(event.getId()).orElseThrow(); + var firstTicketProperties = Map.of("property", "value-first"); + var ticket = new AttendeesByCategory(category.getId(), 1, List.of( + new AttendeeData("firstName", "lastName", "example@example.org", firstTicketProperties) + ), null); + var user = new ReservationUser( + "test@example.org", + "Test", + "McTest", + "test@example.org", + "EXTERNALID" + ); + var creationRequest = new TicketReservationCreationRequest( + List.of(ticket), + List.of(), + null, + user, + null, + "en", + subscriptionId + ); + var principal = new APITokenAuthentication(username, null, List.of()); + var response = controller.createTicketsReservation(event.getShortName(), creationRequest, principal); + assertTrue(response.getStatusCode().is2xxSuccessful()); + var body = response.getBody(); + assertNotNull(body); + assertNull(body.getErrors()); + assertTrue(body.isSuccess()); + var reservationId = body.getId(); + assertNotNull(reservationId); + assertFalse(reservationId.isBlank()); + var href = body.getHref(); + assertFalse(StringUtils.startsWith(href, LOGGED_IN_RESERVATION_URL_PREFIX)); + assertTrue(StringUtils.endsWith(href, "subscription="+subscriptionId)); + var tickets = ticketRepository.findTicketsInReservation(reservationId); + assertEquals(1, tickets.size()); + tickets.forEach(savedTicket -> { + assertEquals("firstName", savedTicket.getFirstName()); + assertEquals("lastName", savedTicket.getLastName()); + assertEquals("example@example.org", savedTicket.getEmail()); + var metadata = ticketRepository.getTicketMetadata(savedTicket.getId()); + assertNotNull(metadata); + var attributes = metadata.getMetadataForKey(TicketMetadataContainer.GENERAL); + assertTrue(attributes.isPresent()); + assertEquals(firstTicketProperties, attributes.get().getAttributes()); + }); + var createdUser = userManager.findOptionalEnabledUserByUsername("test@example.org"); + assertFalse(createdUser.isPresent()); + } + @Test void createSubscriptionWithMetadata() { configurationRepository.insert(ConfigurationKeys.STRIPE_PUBLIC_KEY.getValue(), "pk", ""); diff --git a/src/test/java/alfio/manager/TicketReservationManagerTest.java b/src/test/java/alfio/manager/TicketReservationManagerTest.java index c93d922c2a..5f2f95c3f9 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerTest.java @@ -1148,13 +1148,16 @@ void reservationUrlForExternalClients() { // OpenID active when(maybeOpenId.getValueAsBooleanOrDefault()).thenReturn(true); - Assertions.assertEquals(BASE_URL + "openid/authentication?reservation=" + RESERVATION_ID + "&contextType=" + PurchaseContext.PurchaseContextType.event + "&id=" + shortName, trm.reservationUrlForExternalClients(RESERVATION_ID, event, "en", true)); + Assertions.assertEquals(BASE_URL + "openid/authentication?reservation=" + RESERVATION_ID + "&contextType=" + PurchaseContext.PurchaseContextType.event + "&id=" + shortName, trm.reservationUrlForExternalClients(RESERVATION_ID, event, "en", true, null)); // user not specified in the request - Assertions.assertEquals(BASE_URL + "event/" + shortName + "/reservation/" + RESERVATION_ID + "?lang=en", trm.reservationUrlForExternalClients(RESERVATION_ID, event, "en", false)); + Assertions.assertEquals(BASE_URL + "event/" + shortName + "/reservation/" + RESERVATION_ID + "?lang=en", trm.reservationUrlForExternalClients(RESERVATION_ID, event, "en", false, null)); // OpenID not active when(maybeOpenId.getValueAsBooleanOrDefault()).thenReturn(false); - Assertions.assertEquals(BASE_URL + "event/" + shortName + "/reservation/" + RESERVATION_ID + "?lang=en", trm.reservationUrlForExternalClients(RESERVATION_ID, event, "en", true)); + Assertions.assertEquals(BASE_URL + "event/" + shortName + "/reservation/" + RESERVATION_ID + "?lang=en", trm.reservationUrlForExternalClients(RESERVATION_ID, event, "en", true, null)); + // SubscriptionId is present + var subscriptionId = "subscription-id"; + Assertions.assertEquals(BASE_URL + "event/" + shortName + "/reservation/" + RESERVATION_ID + "?lang=en&subscription=" + subscriptionId, trm.reservationUrlForExternalClients(RESERVATION_ID, event, "en", true, subscriptionId)); } //sendReminderForOptionalInfo From fc30659716339fc7bc828625d1eba00afdc3ec87 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:09:18 +0100 Subject: [PATCH 143/218] fix compilation errors after cherry-pick --- .../alfio/controller/IndexController.java | 6 +- .../api/admin/ResourceController.java | 4 +- .../api/v2/user/TicketApiV2Controller.java | 4 +- .../java/alfio/util/TemplateResource.java | 6 +- src/test/resources/api/descriptor.json | 467 +++++++++--------- 5 files changed, 253 insertions(+), 234 deletions(-) diff --git a/src/main/java/alfio/controller/IndexController.java b/src/main/java/alfio/controller/IndexController.java index be10421f44..a70c37a675 100644 --- a/src/main/java/alfio/controller/IndexController.java +++ b/src/main/java/alfio/controller/IndexController.java @@ -35,6 +35,7 @@ import alfio.util.RequestUtils; import ch.digitalfondue.jfiveparse.*; import org.apache.commons.collections4.IterableUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Profile; import org.springframework.core.io.ClassPathResource; import org.springframework.http.MediaType; @@ -59,6 +60,7 @@ import java.util.regex.Pattern; import static alfio.config.Initializer.PROFILE_LIVE; +import static alfio.controller.Constants.*; import static alfio.model.system.ConfigurationKeys.BASE_CUSTOM_CSS; import static java.util.Objects.requireNonNull; @@ -256,7 +258,9 @@ public void replyToIndex(@PathVariable(value = EVENT_SHORT_NAME, required = fals } @GetMapping("/event/{eventShortName}/reservation/{reservationId}") - public String redirectEventToReservation(@PathVariable(value = EVENT_SHORT_NAME) String eventShortName, @PathVariable(value = "reservationId") String reservationId) { + public String redirectEventToReservation(@PathVariable(value = EVENT_SHORT_NAME) String eventShortName, + @PathVariable(value = "reservationId") String reservationId, + @RequestParam(value = "subscription", required = false) String subscriptionId) { if (eventRepository.existsByShortName(eventShortName)) { var reservationStatusUrlSegment = ticketReservationRepository.findOptionalStatusAndValidationById(reservationId) .map(IndexController::reservationStatusToUrlMapping).orElse(NOT_FOUND); diff --git a/src/main/java/alfio/controller/api/admin/ResourceController.java b/src/main/java/alfio/controller/api/admin/ResourceController.java index 9ac756e5a9..b799234219 100644 --- a/src/main/java/alfio/controller/api/admin/ResourceController.java +++ b/src/main/java/alfio/controller/api/admin/ResourceController.java @@ -86,7 +86,8 @@ public ResourceController(UploadedResourceManager uploadedResourceManager, OrganizationRepository organizationRepository, FileUploadManager fileUploadManager, ExtensionManager extensionManager, - ClockProvider clockProvider) { + ClockProvider clockProvider, + SubscriptionManager subscriptionManager) { this.uploadedResourceManager = uploadedResourceManager; this.userManager = userManager; this.eventRepository = eventRepository; @@ -96,6 +97,7 @@ public ResourceController(UploadedResourceManager uploadedResourceManager, this.fileUploadManager = fileUploadManager; this.extensionManager = extensionManager; this.clockProvider = clockProvider; + this.subscriptionManager = subscriptionManager; } diff --git a/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java index 14bdc388a2..3710fe9c01 100644 --- a/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java @@ -86,7 +86,8 @@ public TicketApiV2Controller(TicketHelper ticketHelper, TemplateManager templateManager, NotificationManager notificationManager, BookingInfoTicketLoader bookingInfoTicketLoader, - TicketRepository ticketRepository) { + TicketRepository ticketRepository, + SubscriptionManager subscriptionManager) { this.ticketHelper = ticketHelper; this.ticketReservationManager = ticketReservationManager; this.ticketCategoryRepository = ticketCategoryRepository; @@ -98,6 +99,7 @@ public TicketApiV2Controller(TicketHelper ticketHelper, this.notificationManager = notificationManager; this.bookingInfoTicketLoader = bookingInfoTicketLoader; this.ticketRepository = ticketRepository; + this.subscriptionManager = subscriptionManager; } diff --git a/src/main/java/alfio/util/TemplateResource.java b/src/main/java/alfio/util/TemplateResource.java index 67c7264786..733efaa21b 100644 --- a/src/main/java/alfio/util/TemplateResource.java +++ b/src/main/java/alfio/util/TemplateResource.java @@ -627,9 +627,9 @@ public static Map buildModelForSubscriptionPDF(Subscription subs model.put(RESERVATION_ID, reservationId); model.put(METADATA_ATTRIBUTES_KEY, metadata.getProperties()); imageData.ifPresent(iData -> { - model.put("logo", iData.getEventImage()); - model.put("imageWidth", iData.getImageWidth()); - model.put("imageHeight", iData.getImageHeight()); + model.put("logo", iData.eventImage); + model.put("imageWidth", iData.imageWidth); + model.put("imageHeight", iData.imageHeight); }); return model; } diff --git a/src/test/resources/api/descriptor.json b/src/test/resources/api/descriptor.json index 0d7eefbffb..a66f01fd08 100644 --- a/src/test/resources/api/descriptor.json +++ b/src/test/resources/api/descriptor.json @@ -7606,7 +7606,7 @@ "required" : true, "schema" : { "type" : "string", - "enum" : [ "GOOGLE_ANALYTICS", "CONFIRMATION_EMAIL_FOR_ORGANIZER", "SEND_RESERVED_CODE", "CONFIRMATION_EMAIL", "CONFIRMATION_EMAIL_SUBSCRIPTION", "OFFLINE_RESERVATION_EXPIRED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL_FOR_ORGANIZER", "CREDIT_NOTE_ISSUED_EMAIL", "OFFLINE_RESERVATION_EXPIRING_EMAIL_FOR_ORGANIZER", "OFFLINE_PAYMENT_MATCHES_FOUND", "REMINDER_EMAIL", "REMINDER_TICKET_ADDITIONAL_INFO", "REMINDER_TICKETS_ASSIGNMENT_EMAIL", "TICKET_EMAIL", "TICKET_EMAIL_FOR_ONLINE_EVENT", "TICKET_HAS_CHANGED_OWNER", "TICKET_HAS_BEEN_CANCELLED", "TICKET_HAS_BEEN_CANCELLED_ADMIN", "TICKET_PDF", "RECEIPT_PDF", "INVOICE_PDF", "CREDIT_NOTE_PDF", "WAITING_QUEUE_JOINED", "WAITING_QUEUE_RESERVATION_EMAIL" ] + "enum" : [ "GOOGLE_ANALYTICS", "CONFIRMATION_EMAIL_FOR_ORGANIZER", "SEND_RESERVED_CODE", "CONFIRMATION_EMAIL", "CONFIRMATION_EMAIL_SUBSCRIPTION", "OFFLINE_RESERVATION_EXPIRED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL_FOR_ORGANIZER", "CREDIT_NOTE_ISSUED_EMAIL", "OFFLINE_RESERVATION_EXPIRING_EMAIL_FOR_ORGANIZER", "OFFLINE_PAYMENT_MATCHES_FOUND", "REMINDER_EMAIL", "REMINDER_TICKET_ADDITIONAL_INFO", "REMINDER_TICKETS_ASSIGNMENT_EMAIL", "TICKET_EMAIL", "TICKET_EMAIL_FOR_ONLINE_EVENT", "TICKET_HAS_CHANGED_OWNER", "TICKET_HAS_BEEN_CANCELLED", "TICKET_HAS_BEEN_CANCELLED_ADMIN", "TICKET_PDF", "RECEIPT_PDF", "INVOICE_PDF", "CREDIT_NOTE_PDF", "SUBSCRIPTION_PDF", "WAITING_QUEUE_JOINED", "WAITING_QUEUE_RESERVATION_EMAIL" ] } }, { "name" : "locale", @@ -7631,6 +7631,14 @@ "type" : "integer", "format" : "int32" } + }, { + "name" : "subscriptionDescriptorId", + "in" : "query", + "required" : false, + "schema" : { + "type" : "string", + "format" : "uuid" + } } ], "requestBody" : { "content" : { @@ -18397,7 +18405,7 @@ "required" : true, "schema" : { "type" : "string", - "enum" : [ "GOOGLE_ANALYTICS", "CONFIRMATION_EMAIL_FOR_ORGANIZER", "SEND_RESERVED_CODE", "CONFIRMATION_EMAIL", "CONFIRMATION_EMAIL_SUBSCRIPTION", "OFFLINE_RESERVATION_EXPIRED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL_FOR_ORGANIZER", "CREDIT_NOTE_ISSUED_EMAIL", "OFFLINE_RESERVATION_EXPIRING_EMAIL_FOR_ORGANIZER", "OFFLINE_PAYMENT_MATCHES_FOUND", "REMINDER_EMAIL", "REMINDER_TICKET_ADDITIONAL_INFO", "REMINDER_TICKETS_ASSIGNMENT_EMAIL", "TICKET_EMAIL", "TICKET_EMAIL_FOR_ONLINE_EVENT", "TICKET_HAS_CHANGED_OWNER", "TICKET_HAS_BEEN_CANCELLED", "TICKET_HAS_BEEN_CANCELLED_ADMIN", "TICKET_PDF", "RECEIPT_PDF", "INVOICE_PDF", "CREDIT_NOTE_PDF", "WAITING_QUEUE_JOINED", "WAITING_QUEUE_RESERVATION_EMAIL" ] + "enum" : [ "GOOGLE_ANALYTICS", "CONFIRMATION_EMAIL_FOR_ORGANIZER", "SEND_RESERVED_CODE", "CONFIRMATION_EMAIL", "CONFIRMATION_EMAIL_SUBSCRIPTION", "OFFLINE_RESERVATION_EXPIRED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL_FOR_ORGANIZER", "CREDIT_NOTE_ISSUED_EMAIL", "OFFLINE_RESERVATION_EXPIRING_EMAIL_FOR_ORGANIZER", "OFFLINE_PAYMENT_MATCHES_FOUND", "REMINDER_EMAIL", "REMINDER_TICKET_ADDITIONAL_INFO", "REMINDER_TICKETS_ASSIGNMENT_EMAIL", "TICKET_EMAIL", "TICKET_EMAIL_FOR_ONLINE_EVENT", "TICKET_HAS_CHANGED_OWNER", "TICKET_HAS_BEEN_CANCELLED", "TICKET_HAS_BEEN_CANCELLED_ADMIN", "TICKET_PDF", "RECEIPT_PDF", "INVOICE_PDF", "CREDIT_NOTE_PDF", "SUBSCRIPTION_PDF", "WAITING_QUEUE_JOINED", "WAITING_QUEUE_RESERVATION_EMAIL" ] } }, { "name" : "locale", @@ -18507,7 +18515,7 @@ "type" : "array", "items" : { "type" : "string", - "enum" : [ "GOOGLE_ANALYTICS", "CONFIRMATION_EMAIL_FOR_ORGANIZER", "SEND_RESERVED_CODE", "CONFIRMATION_EMAIL", "CONFIRMATION_EMAIL_SUBSCRIPTION", "OFFLINE_RESERVATION_EXPIRED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL_FOR_ORGANIZER", "CREDIT_NOTE_ISSUED_EMAIL", "OFFLINE_RESERVATION_EXPIRING_EMAIL_FOR_ORGANIZER", "OFFLINE_PAYMENT_MATCHES_FOUND", "REMINDER_EMAIL", "REMINDER_TICKET_ADDITIONAL_INFO", "REMINDER_TICKETS_ASSIGNMENT_EMAIL", "TICKET_EMAIL", "TICKET_EMAIL_FOR_ONLINE_EVENT", "TICKET_HAS_CHANGED_OWNER", "TICKET_HAS_BEEN_CANCELLED", "TICKET_HAS_BEEN_CANCELLED_ADMIN", "TICKET_PDF", "RECEIPT_PDF", "INVOICE_PDF", "CREDIT_NOTE_PDF", "WAITING_QUEUE_JOINED", "WAITING_QUEUE_RESERVATION_EMAIL" ] + "enum" : [ "GOOGLE_ANALYTICS", "CONFIRMATION_EMAIL_FOR_ORGANIZER", "SEND_RESERVED_CODE", "CONFIRMATION_EMAIL", "CONFIRMATION_EMAIL_SUBSCRIPTION", "OFFLINE_RESERVATION_EXPIRED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL", "CHARGE_ATTEMPT_FAILED_EMAIL_FOR_ORGANIZER", "CREDIT_NOTE_ISSUED_EMAIL", "OFFLINE_RESERVATION_EXPIRING_EMAIL_FOR_ORGANIZER", "OFFLINE_PAYMENT_MATCHES_FOUND", "REMINDER_EMAIL", "REMINDER_TICKET_ADDITIONAL_INFO", "REMINDER_TICKETS_ASSIGNMENT_EMAIL", "TICKET_EMAIL", "TICKET_EMAIL_FOR_ONLINE_EVENT", "TICKET_HAS_CHANGED_OWNER", "TICKET_HAS_BEEN_CANCELLED", "TICKET_HAS_BEEN_CANCELLED_ADMIN", "TICKET_PDF", "RECEIPT_PDF", "INVOICE_PDF", "CREDIT_NOTE_PDF", "SUBSCRIPTION_PDF", "WAITING_QUEUE_JOINED", "WAITING_QUEUE_RESERVATION_EMAIL" ] } } } @@ -25393,15 +25401,15 @@ "location" : { "type" : "string" }, + "description" : { + "type" : "string" + }, "arguments" : { "type" : "array", "items" : { "type" : "object" } }, - "description" : { - "type" : "string" - }, "code" : { "type" : "string" } @@ -25792,7 +25800,13 @@ "refundedAmount" : { "type" : "string" }, - "ticketAmount" : { + "notYetPaid" : { + "type" : "boolean" + }, + "vatExempt" : { + "type" : "boolean" + }, + "priceInCents" : { "type" : "integer", "format" : "int32" }, @@ -25814,13 +25828,7 @@ "priceBeforeTaxes" : { "type" : "string" }, - "notYetPaid" : { - "type" : "boolean" - }, - "vatExempt" : { - "type" : "boolean" - }, - "priceInCents" : { + "ticketAmount" : { "type" : "integer", "format" : "int32" } @@ -26016,13 +26024,13 @@ "valid" : { "type" : "boolean" }, - "formattedValidityTo" : { + "pin" : { "type" : "string" }, - "formattedValidityFrom" : { + "formattedValidityTo" : { "type" : "string" }, - "pin" : { + "formattedValidityFrom" : { "type" : "string" } } @@ -26171,9 +26179,6 @@ "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, "assigned" : { "type" : "boolean" }, @@ -26182,6 +26187,9 @@ }, "formattedFinalPrice" : { "type" : "string" + }, + "formattedNetPrice" : { + "type" : "string" } } }, @@ -26379,15 +26387,6 @@ "cancelled" : { "type" : "boolean" }, - "stuck" : { - "type" : "boolean" - }, - "hasBillingAddress" : { - "type" : "boolean" - }, - "hasVatNumber" : { - "type" : "boolean" - }, "hasInvoiceNumber" : { "type" : "boolean" }, @@ -26409,6 +26408,15 @@ "hasBeenPaid" : { "type" : "boolean" }, + "stuck" : { + "type" : "boolean" + }, + "hasBillingAddress" : { + "type" : "boolean" + }, + "hasVatNumber" : { + "type" : "boolean" + }, "finalPrice" : { "type" : "number" }, @@ -26512,36 +26520,16 @@ "type" : "string", "enum" : [ "PENDING", "IN_PAYMENT", "EXTERNAL_PROCESSING_PAYMENT", "WAITING_EXTERNAL_CONFIRMATION", "OFFLINE_PAYMENT", "DEFERRED_OFFLINE_PAYMENT", "COMPLETE", "STUCK", "CANCELLED", "CREDIT_NOTE_ISSUED" ] }, - "stuck" : { - "type" : "boolean" - }, - "reminderSent" : { - "type" : "boolean" - }, - "hasBillingAddress" : { - "type" : "boolean" - }, - "hasVatNumber" : { - "type" : "boolean" - }, - "latestReminder" : { - "type" : "string", - "format" : "date-time" - }, - "invoiceModel" : { - "type" : "string" - }, - "usedVatPercent" : { - "type" : "number" - }, - "creationTimestamp" : { - "type" : "string", - "format" : "date-time" - }, "promoCodeDiscountId" : { "type" : "integer", "format" : "int32" }, + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, "hasInvoiceNumber" : { "type" : "boolean" }, @@ -26552,18 +26540,6 @@ "type" : "string", "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "email" : { - "type" : "string" - }, - "userLanguage" : { - "type" : "string" - }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] @@ -26617,6 +26593,12 @@ "netPrice" : { "type" : "number" }, + "email" : { + "type" : "string" + }, + "userLanguage" : { + "type" : "string" + }, "validity" : { "type" : "string", "format" : "date-time" @@ -26658,6 +26640,32 @@ }, "taxablePrice" : { "type" : "number" + }, + "stuck" : { + "type" : "boolean" + }, + "reminderSent" : { + "type" : "boolean" + }, + "hasBillingAddress" : { + "type" : "boolean" + }, + "hasVatNumber" : { + "type" : "boolean" + }, + "latestReminder" : { + "type" : "string", + "format" : "date-time" + }, + "invoiceModel" : { + "type" : "string" + }, + "usedVatPercent" : { + "type" : "number" + }, + "creationTimestamp" : { + "type" : "string", + "format" : "date-time" } } }, @@ -27995,6 +28003,9 @@ "language" : { "type" : "string" }, + "subscriptionId" : { + "type" : "string" + }, "reservationConfiguration" : { "$ref" : "#/components/schemas/ReservationConfiguration" }, @@ -28380,12 +28391,6 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "tags" : { "type" : "array", "items" : { @@ -28409,19 +28414,6 @@ "type" : "string", "format" : "uuid" }, - "email" : { - "type" : "string" - }, - "userLanguage" : { - "type" : "string" - }, - "categoryId" : { - "type" : "integer", - "format" : "int32" - }, - "ticketsReservationId" : { - "type" : "string" - }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] @@ -28442,6 +28434,19 @@ "type" : "integer", "format" : "int32" }, + "email" : { + "type" : "string" + }, + "userLanguage" : { + "type" : "string" + }, + "categoryId" : { + "type" : "integer", + "format" : "int32" + }, + "ticketsReservationId" : { + "type" : "string" + }, "uuid" : { "type" : "string" }, @@ -28458,6 +28463,12 @@ "formattedFinalPrice" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "categoryName" : { "type" : "string" } @@ -29703,12 +29714,6 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "tags" : { "type" : "array", "items" : { @@ -29732,19 +29737,6 @@ "type" : "string", "format" : "uuid" }, - "email" : { - "type" : "string" - }, - "userLanguage" : { - "type" : "string" - }, - "categoryId" : { - "type" : "integer", - "format" : "int32" - }, - "ticketsReservationId" : { - "type" : "string" - }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] @@ -29765,6 +29757,19 @@ "type" : "integer", "format" : "int32" }, + "email" : { + "type" : "string" + }, + "userLanguage" : { + "type" : "string" + }, + "categoryId" : { + "type" : "integer", + "format" : "int32" + }, + "ticketsReservationId" : { + "type" : "string" + }, "uuid" : { "type" : "string" }, @@ -29780,6 +29785,12 @@ }, "formattedFinalPrice" : { "type" : "string" + }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" } } }, @@ -30494,9 +30505,6 @@ "type" : "string", "enum" : [ "STANDARD", "CUSTOM", "NOT_SET" ] }, - "formattedPrice" : { - "type" : "string" - }, "assignmentConfiguration" : { "$ref" : "#/components/schemas/AssignmentConfiguration" }, @@ -30506,6 +30514,9 @@ "canApplySubscriptions" : { "type" : "boolean" }, + "formattedPrice" : { + "type" : "string" + }, "contentLanguages" : { "type" : "array", "items" : { @@ -31638,18 +31649,6 @@ "displayName" : { "type" : "string" }, - "titleAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, - "descriptionAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, "publicIdentifier" : { "type" : "string" }, @@ -31676,6 +31675,18 @@ "freeOfCharge" : { "type" : "boolean" }, + "titleAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, + "descriptionAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, "fileBlobIdIsPresent" : { "type" : "boolean" }, @@ -31780,15 +31791,6 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, - "stuck" : { - "type" : "boolean" - }, "tags" : { "type" : "array", "items" : { @@ -31815,19 +31817,6 @@ "type" : "string", "format" : "uuid" }, - "email" : { - "type" : "string" - }, - "userLanguage" : { - "type" : "string" - }, - "categoryId" : { - "type" : "integer", - "format" : "int32" - }, - "ticketsReservationId" : { - "type" : "string" - }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] @@ -31851,6 +31840,19 @@ "type" : "integer", "format" : "int32" }, + "email" : { + "type" : "string" + }, + "userLanguage" : { + "type" : "string" + }, + "categoryId" : { + "type" : "integer", + "format" : "int32" + }, + "ticketsReservationId" : { + "type" : "string" + }, "uuid" : { "type" : "string" }, @@ -31867,6 +31869,15 @@ "formattedFinalPrice" : { "type" : "string" }, + "stuck" : { + "type" : "boolean" + }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "transactionTimestamp" : { "type" : "string", "format" : "date-time" @@ -31988,12 +31999,6 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "tags" : { "type" : "array", "items" : { @@ -32017,19 +32022,6 @@ "type" : "string", "format" : "uuid" }, - "email" : { - "type" : "string" - }, - "userLanguage" : { - "type" : "string" - }, - "categoryId" : { - "type" : "integer", - "format" : "int32" - }, - "ticketsReservationId" : { - "type" : "string" - }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] @@ -32050,6 +32042,19 @@ "type" : "integer", "format" : "int32" }, + "email" : { + "type" : "string" + }, + "userLanguage" : { + "type" : "string" + }, + "categoryId" : { + "type" : "integer", + "format" : "int32" + }, + "ticketsReservationId" : { + "type" : "string" + }, "uuid" : { "type" : "string" }, @@ -32066,6 +32071,12 @@ "formattedFinalPrice" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "additionalFields" : { "type" : "object", "additionalProperties" : { @@ -32788,15 +32799,6 @@ "description" : { "type" : "string" }, - "formattedStart" : { - "type" : "string" - }, - "formattedEnd" : { - "type" : "string" - }, - "formattedDiscountAmount" : { - "type" : "string" - }, "eventId" : { "type" : "integer", "format" : "int32" @@ -32855,6 +32857,15 @@ }, "fixedAmount" : { "type" : "boolean" + }, + "formattedStart" : { + "type" : "string" + }, + "formattedEnd" : { + "type" : "string" + }, + "formattedDiscountAmount" : { + "type" : "string" } } }, @@ -33141,32 +33152,9 @@ "type" : "string", "enum" : [ "DRAFT", "PUBLIC", "DISABLED" ] }, - "notSoldTickets" : { - "type" : "integer", - "format" : "int32" - }, - "soldTickets" : { - "type" : "integer", - "format" : "int32" - }, - "pendingTickets" : { - "type" : "integer", - "format" : "int32" - }, - "dynamicAllocation" : { - "type" : "integer", - "format" : "int32" - }, - "releasedTickets" : { - "type" : "integer", - "format" : "int32" - }, "shortName" : { "type" : "string" }, - "formattedEnd" : { - "type" : "string" - }, "organizationId" : { "type" : "integer", "format" : "int32" @@ -33196,15 +33184,38 @@ "expired" : { "type" : "boolean" }, - "warningNeeded" : { - "type" : "boolean" + "notSoldTickets" : { + "type" : "integer", + "format" : "int32" }, - "formattedBegin" : { + "soldTickets" : { + "type" : "integer", + "format" : "int32" + }, + "pendingTickets" : { + "type" : "integer", + "format" : "int32" + }, + "dynamicAllocation" : { + "type" : "integer", + "format" : "int32" + }, + "releasedTickets" : { + "type" : "integer", + "format" : "int32" + }, + "formattedEnd" : { "type" : "string" }, "visibleForCurrentUser" : { "type" : "boolean" }, + "warningNeeded" : { + "type" : "boolean" + }, + "formattedBegin" : { + "type" : "string" + }, "displayStatistics" : { "type" : "boolean" } @@ -33443,6 +33454,9 @@ "inputType" : { "type" : "string" }, + "countryField" : { + "type" : "boolean" + }, "inputField" : { "type" : "boolean" }, @@ -33463,9 +33477,6 @@ }, "minLengthDefined" : { "type" : "boolean" - }, - "countryField" : { - "type" : "boolean" } } }, @@ -33517,6 +33528,35 @@ "type" : "integer", "format" : "int32" }, + "required" : { + "type" : "boolean" + }, + "eventId" : { + "type" : "integer", + "format" : "int32" + }, + "additionalServiceId" : { + "type" : "integer", + "format" : "int32" + }, + "countryField" : { + "type" : "boolean" + }, + "restrictedValues" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "editable" : { + "type" : "boolean" + }, + "disabledValues" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, "inputField" : { "type" : "boolean" }, @@ -33544,35 +33584,6 @@ "type" : "integer", "format" : "int32" } - }, - "required" : { - "type" : "boolean" - }, - "disabledValues" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "eventId" : { - "type" : "integer", - "format" : "int32" - }, - "additionalServiceId" : { - "type" : "integer", - "format" : "int32" - }, - "countryField" : { - "type" : "boolean" - }, - "restrictedValues" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "editable" : { - "type" : "boolean" } } }, From e7a1fd97d99958a8b5e65306c3e51278c91c2b37 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Fri, 3 Feb 2023 19:49:53 +0100 Subject: [PATCH 144/218] API to retrieve check-in log (#1188) (cherry-picked from 976f88a03f1d5ab9ac239cbe64708f79941d473e) --- .../api/v1/admin/EventApiV1Controller.java | 13 +++++ .../java/alfio/manager/CheckInManager.java | 8 +++ .../model/api/v1/admin/CheckInLogEntry.java | 52 +++++++++++++++++++ .../java/alfio/model/audit/ScanAudit.java | 20 ++++--- .../repository/audit/ScanAuditRepository.java | 9 ++++ .../reservation/BaseReservationFlowTest.java | 8 ++- .../ReservationFlowIntegrationTest.java | 19 ++++++- 7 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java diff --git a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java index 989899a2b0..358101e856 100644 --- a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java +++ b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java @@ -25,6 +25,7 @@ import alfio.manager.user.UserManager; import alfio.model.*; import alfio.model.ExtensionSupport.ExtensionMetadataValue; +import alfio.model.api.v1.admin.CheckInLogEntry; import alfio.model.api.v1.admin.EventCreationRequest; import alfio.model.api.v1.admin.LinkedSubscriptions; import alfio.model.group.Group; @@ -76,6 +77,7 @@ public class EventApiV1Controller { private final ExtensionRepository extensionRepository; private final ConfigurationManager configurationManager; private final AdminJobManager adminJobManager; + private final CheckInManager checkInManager; public EventApiV1Controller(EventManager eventManager, EventNameManager eventNameManager, @@ -223,6 +225,17 @@ public ResponseEntity generateTicketsForSubscribers(@PathVariable("slug })); } + @GetMapping("/{slug}/check-in-log") + public ResponseEntity> checkInLog(@PathVariable("slug") String slug, + Principal user) { + try { + return ResponseEntity.ok(checkInManager.retrieveLogEntries(slug, user.getName())); + } catch (Exception ex) { + log.error("Error while loading check-in log entries", ex); + return ResponseEntity.internalServerError().build(); + } + } + private LinkedSubscriptions retrieveLinkedSubscriptionsForEvent(String slug, int id, int organizationId) { var subscriptionIds = eventManager.getLinkedSubscriptionIds(id, organizationId); return new LinkedSubscriptions(slug, subscriptionIds); diff --git a/src/main/java/alfio/manager/CheckInManager.java b/src/main/java/alfio/manager/CheckInManager.java index c7fd92d9ee..80b4f72cf8 100644 --- a/src/main/java/alfio/manager/CheckInManager.java +++ b/src/main/java/alfio/manager/CheckInManager.java @@ -20,6 +20,7 @@ import alfio.manager.system.ConfigurationManager; import alfio.model.*; import alfio.model.Ticket.TicketStatus; +import alfio.model.api.v1.admin.CheckInLogEntry; import alfio.model.audit.ScanAudit; import alfio.model.checkin.AttendeeSearchResults; import alfio.model.decorator.TicketPriceContainer; @@ -565,6 +566,13 @@ public CheckInStatistics getStatistics(String eventName, String username) { .orElse(null); } + public List retrieveLogEntries(String eventName, String username) { + return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) + .filter(EventManager.checkOwnership(username, organizationRepository)) + .map(event -> scanAuditRepository.loadEntries(event.getId())) + .orElse(List.of()); + } + private boolean areStatsEnabled(EventAndOrganizationId event) { return configurationManager.getFor(CHECK_IN_STATS, event.getConfigurationLevel()).getValueAsBooleanOrDefault(); } diff --git a/src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java b/src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java new file mode 100644 index 0000000000..85100e34df --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java @@ -0,0 +1,52 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +import alfio.model.audit.ScanAudit; +import alfio.model.modification.AttendeeData; +import alfio.model.support.JSONData; +import alfio.util.Json; +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.List; + +public class CheckInLogEntry { + private final String ticketId; + private final AttendeeData attendeeData; + private final List audit; + + public CheckInLogEntry(@Column("t_uuid") String ticketId, + @Column("attendee_data") @JSONData AttendeeData attendeeData, + @Column("scans") String scansAsString) { + this.ticketId = ticketId; + this.attendeeData = attendeeData; + this.audit = Json.fromJson(scansAsString, new TypeReference<>() {}); + } + + public String getTicketId() { + return ticketId; + } + + public AttendeeData getAttendeeData() { + return attendeeData; + } + + public List getAudit() { + return audit; + } +} diff --git a/src/main/java/alfio/model/audit/ScanAudit.java b/src/main/java/alfio/model/audit/ScanAudit.java index e8f63e8043..d0fef5e6e9 100644 --- a/src/main/java/alfio/model/audit/ScanAudit.java +++ b/src/main/java/alfio/model/audit/ScanAudit.java @@ -18,19 +18,25 @@ import alfio.manager.support.CheckInStatus; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.ZonedDateTime; +import java.time.LocalDateTime; public record ScanAudit( - @Column("ticket_uuid") String ticketUuid, - @Column("event_id_fk") int eventId, - @Column("scan_ts") ZonedDateTime scanTimestamp, - @Column("username") String username, - @Column("check_in_status") CheckInStatus checkInStatus, - @Column("operation") ScanAudit.Operation operation) { + @JsonProperty("ticketUuid") @Column("ticket_uuid") String ticketUuid, + @JsonProperty("scanTimestamp") @Column("scan_ts") LocalDateTime scanTimestamp, + @JsonProperty("username") @Column("username") String username, + @JsonProperty("checkInStatus") @Column("check_in_status") CheckInStatus checkInStatus, + @JsonProperty("operation") @Column("operation") ScanAudit.Operation operation) { public enum Operation { SCAN, REVERT } + + @JsonIgnore + public String ticketUuid() { + return ticketUuid; + } } diff --git a/src/main/java/alfio/repository/audit/ScanAuditRepository.java b/src/main/java/alfio/repository/audit/ScanAuditRepository.java index eca3813687..fce7a42d31 100644 --- a/src/main/java/alfio/repository/audit/ScanAuditRepository.java +++ b/src/main/java/alfio/repository/audit/ScanAuditRepository.java @@ -17,6 +17,7 @@ package alfio.repository.audit; import alfio.manager.support.CheckInStatus; +import alfio.model.api.v1.admin.CheckInLogEntry; import alfio.model.audit.ScanAudit; import ch.digitalfondue.npjt.Bind; import ch.digitalfondue.npjt.Query; @@ -38,4 +39,12 @@ Integer insert(@Bind("ticketUuid") String ticketUuid, @Query("select * from scan_audit where event_id_fk = :eventId") List findAllForEvent(@Bind("eventId") int eventId); + @Query("select t.uuid t_uuid, jsonb_build_object('firstName', t.first_name, 'lastName', t.last_name, 'email', t.email_address, 'metadata', coalesce(t.metadata::jsonb#>'{metadataMap, general, attributes}', '{}')) attendee_data, jsonb_agg(jsonb_build_object('ticketUuid', sa.ticket_uuid, 'scanTimestamp', sa.scan_ts, 'username', sa.username, 'checkInStatus', sa.check_in_status, 'operation', sa.operation)) scans from ticket t\n" + + " join event e on t.event_id = e.id" + + " join scan_audit sa on e.id = sa.event_id_fk and t.uuid = sa.ticket_uuid" + + " where e.id = :eventId" + + " and t.status = 'CHECKED_IN'" + + " group by 1,2") + List loadEntries(@Bind("eventId") int eventId); + } \ No newline at end of file diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java index 17bc3235d8..fadf4a5de1 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java @@ -1067,7 +1067,7 @@ protected void testBasicFlow(Supplier contextSupplier) t assertEquals(CheckInStatus.OK_READY_TO_BE_CHECKED_IN, ticketAndCheckInResult.getResult().getStatus()); CheckInApiController.TicketCode tc = new CheckInApiController.TicketCode(); tc.setCode(ticketCode); - assertEquals(CheckInStatus.SUCCESS, checkInApiController.checkIn(context.event.getId(), ticketIdentifier, tc, new TestingAuthenticationToken("ciccio", "ciccio")).getResult().getStatus()); + assertEquals(CheckInStatus.SUCCESS, checkInApiController.checkIn(context.event.getId(), ticketIdentifier, tc, new TestingAuthenticationToken(context.userId + "_api", "")).getResult().getStatus()); List audits = scanAuditRepository.findAllForEvent(context.event.getId()); assertFalse(audits.isEmpty()); assertTrue(audits.stream().anyMatch(sa -> sa.ticketUuid().equals(ticketIdentifier))); @@ -1075,7 +1075,7 @@ protected void testBasicFlow(Supplier contextSupplier) t extLogs = extensionLogRepository.getPage(null, null, null, 100, 0); assertEventLogged(extLogs, TICKET_CHECKED_IN, 2); - + validateCheckInData(context); TicketAndCheckInResult ticketAndCheckInResultOk = checkInApiController.findTicketWithUUID(context.event.getId(), ticketIdentifier, ticketCode); assertEquals(CheckInStatus.ALREADY_CHECK_IN, ticketAndCheckInResultOk.getResult().getStatus()); @@ -1265,6 +1265,10 @@ protected void testBasicFlow(Supplier contextSupplier) t } + protected void validateCheckInData(ReservationFlowContext context) { + + } + protected void performAndValidatePayment(ReservationFlowContext context, String reservationId, int promoCodeId, diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java index 4e4b0af64f..16596357d0 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java @@ -62,6 +62,8 @@ import java.util.List; import static alfio.test.util.IntegrationTestUtil.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; @SpringBootTest @ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class, ControllerConfiguration.class}) @@ -71,6 +73,7 @@ class ReservationFlowIntegrationTest extends BaseReservationFlowTest { private final OrganizationRepository organizationRepository; private final UserManager userManager; + private final CheckInManager checkInManager; @Autowired public ReservationFlowIntegrationTest(OrganizationRepository organizationRepository, @@ -109,7 +112,8 @@ public ReservationFlowIntegrationTest(OrganizationRepository organizationReposit UserRepository userRepository, OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, - PromoCodeRequestManager promoCodeRequestManager) { + PromoCodeRequestManager promoCodeRequestManager, + CheckInManager checkInManager) { super(configurationRepository, eventManager, eventRepository, @@ -147,6 +151,7 @@ public ReservationFlowIntegrationTest(OrganizationRepository organizationReposit promoCodeRequestManager); this.organizationRepository = organizationRepository; this.userManager = userManager; + this.checkInManager = checkInManager; } private ReservationFlowContext createContext() { @@ -174,4 +179,16 @@ protected void performAdditionalTests(ReservationFlowContext context) { var event = context.event; BaseIntegrationTest.testTransferEventToAnotherOrg(event.getId(), event.getOrganizationId(), context.userId, jdbcTemplate); } + + @Override + protected void validateCheckInData(ReservationFlowContext context) { + var entries = checkInManager.retrieveLogEntries(context.event.getShortName(), context.userId); + assertEquals(1, entries.size()); + var entry = entries.get(0); + assertNotNull(entry.getTicketId()); + assertNotNull(entry.getAttendeeData()); + assertNotNull(entry.getAttendeeData().getMetadata()); + assertNotNull(entry.getAudit()); + entry.getAudit().forEach(audit -> assertEquals(context.userId + "_api", audit.getUsername())); + } } From c7c45dab0878b56a28bdf28a8b5aa233b44d03c0 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sat, 4 Feb 2023 16:51:25 +0100 Subject: [PATCH 145/218] fix compilation errors after cherry-pick --- .../api/v1/admin/EventApiV1Controller.java | 6 +- .../ReservationFlowIntegrationTest.java | 2 +- src/test/resources/api/descriptor.json | 197 ++++++++++++++---- 3 files changed, 158 insertions(+), 47 deletions(-) diff --git a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java index 358101e856..a931cc457e 100644 --- a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java +++ b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java @@ -89,7 +89,8 @@ public EventApiV1Controller(EventManager eventManager, ExtensionService extensionService, ExtensionRepository extensionRepository, ConfigurationManager configurationManager, - AdminJobManager adminJobManager) { + AdminJobManager adminJobManager, + CheckInManager checkInManager) { this.eventManager = eventManager; this.eventNameManager = eventNameManager; this.fileUploadManager = fileUploadManager; @@ -101,6 +102,7 @@ public EventApiV1Controller(EventManager eventManager, this.extensionRepository = extensionRepository; this.configurationManager = configurationManager; this.adminJobManager = adminJobManager; + this.checkInManager = checkInManager; } @PostMapping("/create") @@ -338,7 +340,7 @@ private Optional insertEvent(EventCreationRequest request, Principal user return pair.getRight().isPresent(); }) .map(pair -> new ExtensionMetadataValue(pair.getRight().get().getId(), pair.getLeft().getValue())) - .collect(Collectors.toList()); + .toList(); extensionService.bulkUpdateEventSettings(organization, e, values); }); diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java index 16596357d0..9b82d6f473 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java @@ -189,6 +189,6 @@ protected void validateCheckInData(ReservationFlowContext context) { assertNotNull(entry.getAttendeeData()); assertNotNull(entry.getAttendeeData().getMetadata()); assertNotNull(entry.getAudit()); - entry.getAudit().forEach(audit -> assertEquals(context.userId + "_api", audit.getUsername())); + entry.getAudit().forEach(audit -> assertEquals(context.userId + "_api", audit.username())); } } diff --git a/src/test/resources/api/descriptor.json b/src/test/resources/api/descriptor.json index a66f01fd08..a99166a4dd 100644 --- a/src/test/resources/api/descriptor.json +++ b/src/test/resources/api/descriptor.json @@ -14952,6 +14952,75 @@ } } }, + "/api/v1/admin/event/{slug}/check-in-log" : { + "get" : { + "tags" : [ "event-api-v-1-controller" ], + "operationId" : "checkInLog", + "parameters" : [ { + "name" : "slug", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/CheckInLogEntry" + } + } + } + } + } + } + } + }, "/api/reservation/{reservationId}/payment/{method}/status" : { "get" : { "tags" : [ "payment-api-controller" ], @@ -25401,15 +25470,15 @@ "location" : { "type" : "string" }, - "description" : { - "type" : "string" - }, "arguments" : { "type" : "array", "items" : { "type" : "object" } }, + "description" : { + "type" : "string" + }, "code" : { "type" : "string" } @@ -26085,12 +26154,12 @@ "taxPercentage" : { "type" : "string" }, - "discount" : { - "type" : "boolean" - }, "descriptionForPayment" : { "type" : "string" }, + "discount" : { + "type" : "boolean" + }, "taxDetail" : { "type" : "boolean" } @@ -26524,6 +26593,10 @@ "type" : "integer", "format" : "int32" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "firstName" : { "type" : "string" }, @@ -26540,10 +26613,6 @@ "type" : "string", "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -28400,6 +28469,10 @@ "assigned" : { "type" : "boolean" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -28414,10 +28487,6 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -29723,6 +29792,10 @@ "assigned" : { "type" : "boolean" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -29737,10 +29810,6 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -31649,15 +31718,15 @@ "displayName" : { "type" : "string" }, - "publicIdentifier" : { - "type" : "string" - }, "contentLanguages" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ContentLanguage" } }, + "publicIdentifier" : { + "type" : "string" + }, "allowedPaymentProxies" : { "type" : "array", "items" : { @@ -31803,6 +31872,10 @@ "transaction" : { "$ref" : "#/components/schemas/Transaction" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -31817,10 +31890,6 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -31869,18 +31938,14 @@ "formattedFinalPrice" : { "type" : "string" }, - "stuck" : { - "type" : "boolean" - }, "formattedNetPrice" : { "type" : "string" }, "extReference" : { "type" : "string" }, - "transactionTimestamp" : { - "type" : "string", - "format" : "date-time" + "stuck" : { + "type" : "boolean" }, "paid" : { "type" : "boolean" @@ -31888,6 +31953,10 @@ "pending" : { "type" : "boolean" }, + "transactionTimestamp" : { + "type" : "string", + "format" : "date-time" + }, "netPrice" : { "type" : "number" }, @@ -31959,6 +32028,46 @@ } } }, + "CheckInLogEntry" : { + "type" : "object", + "properties" : { + "ticketId" : { + "type" : "string" + }, + "attendeeData" : { + "$ref" : "#/components/schemas/AttendeeData" + }, + "audit" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/ScanAudit" + } + } + } + }, + "ScanAudit" : { + "type" : "object", + "properties" : { + "ticketUuid" : { + "type" : "string" + }, + "scanTimestamp" : { + "type" : "string", + "format" : "date-time" + }, + "username" : { + "type" : "string" + }, + "checkInStatus" : { + "type" : "string", + "enum" : [ "EVENT_NOT_FOUND", "TICKET_NOT_FOUND", "EMPTY_TICKET_CODE", "INVALID_TICKET_CODE", "INVALID_TICKET_STATE", "ALREADY_CHECK_IN", "MUST_PAY", "OK_READY_TO_BE_CHECKED_IN", "SUCCESS", "INVALID_TICKET_CATEGORY_CHECK_IN_DATE", "BADGE_SCAN_ALREADY_DONE", "OK_READY_FOR_BADGE_SCAN", "BADGE_SCAN_SUCCESS", "ERROR" ] + }, + "operation" : { + "type" : "string", + "enum" : [ "SCAN", "REVERT" ] + } + } + }, "ResultTicketWithAdditionalFields" : { "type" : "object", "properties" : { @@ -32008,6 +32117,10 @@ "assigned" : { "type" : "boolean" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -32022,10 +32135,6 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -33207,15 +33316,15 @@ "formattedEnd" : { "type" : "string" }, - "visibleForCurrentUser" : { - "type" : "boolean" - }, "warningNeeded" : { "type" : "boolean" }, "formattedBegin" : { "type" : "string" }, + "visibleForCurrentUser" : { + "type" : "boolean" + }, "displayStatistics" : { "type" : "boolean" } @@ -33722,18 +33831,18 @@ "type" : "string" } }, - "publicIdentifier" : { - "type" : "string" - }, - "free" : { - "type" : "boolean" - }, "contentLanguages" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ContentLanguage" } }, + "publicIdentifier" : { + "type" : "string" + }, + "free" : { + "type" : "boolean" + }, "privacyPolicyLinkOrNull" : { "type" : "string" }, From f8bac1b0ece63899b42338bd5cc1631a626ff5f7 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sat, 4 Feb 2023 19:21:53 +0100 Subject: [PATCH 146/218] Improve Event API (cherry-picked from e1e6b4d80b0bc403b9f9f8dd529946c0a65a7236) --- .../api/v1/admin/EventApiV1Controller.java | 78 +++++---- .../api/v1/admin/EventCreationRequest.java | 113 ++++++++----- .../api/v1/EventApiV1IntegrationTest.java | 155 ++++++++++++++++-- 3 files changed, 253 insertions(+), 93 deletions(-) diff --git a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java index a931cc457e..7971e6b28b 100644 --- a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java +++ b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java @@ -23,8 +23,11 @@ import alfio.manager.system.ConfigurationLevel; import alfio.manager.system.ConfigurationManager; import alfio.manager.user.UserManager; -import alfio.model.*; +import alfio.model.Event; +import alfio.model.EventWithAdditionalInfo; +import alfio.model.ExtensionSupport; import alfio.model.ExtensionSupport.ExtensionMetadataValue; +import alfio.model.PromoCodeDiscount; import alfio.model.api.v1.admin.CheckInLogEntry; import alfio.model.api.v1.admin.EventCreationRequest; import alfio.model.api.v1.admin.LinkedSubscriptions; @@ -56,6 +59,7 @@ import static alfio.controller.api.admin.EventApiController.validateEvent; import static alfio.manager.system.AdminJobExecutor.JobName.ASSIGN_TICKETS_TO_SUBSCRIBERS; +import static alfio.model.api.v1.admin.EventCreationRequest.findExistingCategory; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -121,6 +125,7 @@ public ResponseEntity create(@RequestBody EventCreationRequest request, .checkPrecondition(() -> isNotBlank(request.getImageUrl()), ErrorCode.custom("invalid.imageUrl", "Invalid Image URL")) .checkPrecondition(() -> isNotBlank(request.getTimezone()), ErrorCode.custom("invalid.timezone", "Invalid Timezone")) .checkPrecondition(() -> isNotBlank(imageRef), ErrorCode.custom("invalid.image", "Image is either missing or too big (max 200kb)")) + .checkPrecondition(() -> validateCategoriesSalesPeriod(request), ErrorCode.custom("invalid.categories", "Ticket categories: sales period not compatible with event dates")) .checkPrecondition(() -> { EventModification eventModification = request.toEventModification(organization, eventNameManager::generateShortName, imageRef); errorsContainer.set(new BeanPropertyBindingResult(eventModification, "event")); @@ -133,7 +138,7 @@ public ResponseEntity create(@RequestBody EventCreationRequest request, }, ErrorCode.lazy(() -> toErrorCode(errorsContainer.get()))) //TODO all location validation //TODO language validation, for all the description the same languages - .build(() -> insertEvent(request, user, imageRef).map(Event::getShortName).orElseThrow(IllegalStateException::new)); + .build(() -> insertEvent(request, user, imageRef).orElseThrow(IllegalStateException::new)); if(result.isSuccess()) { return ResponseEntity.ok(result.getData()); @@ -143,6 +148,12 @@ public ResponseEntity create(@RequestBody EventCreationRequest request, } + private boolean validateCategoriesSalesPeriod(EventCreationRequest request) { + var eventEnd = request.getEndDate(); + return request.getTickets().getCategories().stream() + .allMatch(tc -> tc.getStartSellingDate().isBefore(tc.getEndSellingDate()) && tc.getEndSellingDate().isBefore(eventEnd)); + } + private ErrorCode toErrorCode(Errors errors) { return errors.getFieldErrors().stream() .map(e -> ErrorCode.custom(e.getField(), e.getCode())) @@ -183,7 +194,7 @@ public ResponseEntity update(@PathVariable("slug") String slug, @Request String imageRef = fetchImage(request.getImageUrl()); Result result = new Result.Builder() - .build(() -> updateEvent(slug, request, user, imageRef).map(Event::getShortName).get()); + .build(() -> updateEvent(slug, request, user, imageRef).map(Event::getShortName).orElseThrow()); if(result.isSuccess()) { return ResponseEntity.ok(result.getData()); @@ -250,18 +261,22 @@ private Optional updateEvent(String slug, EventCreationRequest request, P Event event = original.getEvent(); - EventModification em = request.toEventModificationUpdate(original,organization,imageRef); + EventModification em = request.toEventModificationUpdate(original, organization, imageRef); eventManager.updateEventHeader(event, em, user.getName()); eventManager.updateEventPrices(event, em, user.getName()); if (em.getTicketCategories() != null && !em.getTicketCategories().isEmpty()) { - em.getTicketCategories().forEach(c -> - findCategoryByName(event, c.getName()).ifPresent(originalCategory -> - eventManager.updateCategory(originalCategory.getId(), event.getId(), c, user.getName()) - ) - ); + var existingCategories = original.getTicketCategories(); + em.getTicketCategories().forEach(c -> { + var existingCategory = findExistingCategory(existingCategories, c.getName(), c.getId()); + if (existingCategory.isPresent()) { + eventManager.updateCategory(existingCategory.get().getId(), event.getId(), c, user.getName()); + } else { + eventManager.insertCategory(event.getId(), c, user.getName()); + } + }); } @@ -270,26 +285,21 @@ private Optional updateEvent(String slug, EventCreationRequest request, P return eventManager.getOptionalByName(slug,user.getName()); } - private Optional findCategoryByName(Event event, String name) { - List categories = eventManager.loadTicketCategories(event); - return categories.stream().filter( oc -> oc.getName().equals(name)).findFirst(); - } - - private Optional insertEvent(EventCreationRequest request, Principal user, String imageRef) { - Organization organization = userManager.findUserOrganizations(user.getName()).get(0); - EventModification em = request.toEventModification(organization,eventNameManager::generateShortName,imageRef); - eventManager.createEvent(em, user.getName()); - Optional event = eventManager.getOptionalByName(em.getShortName(),user.getName()); - - event.ifPresent(e -> { + private Optional insertEvent(EventCreationRequest request, Principal user, String imageRef) { + try { + Organization organization = userManager.findUserOrganizations(user.getName()).get(0); + EventModification em = request.toEventModification(organization,eventNameManager::generateShortName,imageRef); + eventManager.createEvent(em, user.getName()); + var eventWithStatistics = eventStatisticsManager.getEventWithAdditionalInfo(em.getShortName(),user.getName()); + var event = eventWithStatistics.getEvent(); Optional.ofNullable(request.getTickets().getPromoCodes()).ifPresent(promoCodes -> promoCodes.forEach(pc -> //TODO add ref to categories eventManager.addPromoCode( pc.getName(), - e.getId(), + event.getId(), organization.getId(), - ZonedDateTime.of(pc.getValidFrom(),e.getZoneId()), - ZonedDateTime.of(pc.getValidTo(),e.getZoneId()), + ZonedDateTime.of(pc.getValidFrom(),event.getZoneId()), + ZonedDateTime.of(pc.getValidTo(),event.getZoneId()), pc.getDiscount(), pc.getDiscountType(), Collections.emptyList(), @@ -298,7 +308,7 @@ private Optional insertEvent(EventCreationRequest request, Principal user null, PromoCodeDiscount.CodeType.DISCOUNT, null, - pc.getDiscountType() != PromoCodeDiscount.DiscountType.PERCENTAGE ? e.getCurrency() : null + pc.getDiscountType() != PromoCodeDiscount.DiscountType.PERCENTAGE ? event.getCurrency() : null ) ) ); @@ -310,16 +320,16 @@ private Optional insertEvent(EventCreationRequest request, Principal user if(link.getRight().isPresent()) { Group group = link.getRight().get(); EventCreationRequest.CategoryRequest categoryRequest = link.getLeft(); - findCategoryByName(e, categoryRequest.getName()).ifPresent(category -> { + findExistingCategory(eventWithStatistics.getTicketCategories(), categoryRequest.getName(), categoryRequest.getId()).ifPresent(category -> { EventCreationRequest.GroupLinkRequest groupLinkRequest = categoryRequest.getGroupLink(); LinkedGroupModification modification = new LinkedGroupModification(null, group.getId(), - e.getId(), + event.getId(), category.getId(), groupLinkRequest.getType(), groupLinkRequest.getMatchType(), groupLinkRequest.getMaxAllocation()); - groupManager.createLink(group.getId(), e.getId(), modification); + groupManager.createLink(group.getId(), event.getId(), modification); }); } }); @@ -327,7 +337,7 @@ private Optional insertEvent(EventCreationRequest request, Principal user request.getExtensionSettings().stream() .collect(Collectors.groupingBy(EventCreationRequest.ExtensionSetting::getExtensionId)) .forEach((id,settings) -> { - List metadata = extensionService.getSingle(organization, e, id) + List metadata = extensionService.getSingle(organization, event, id) .map(es -> extensionRepository.findAllParametersForExtension(es.getId())) .orElseGet(Collections::emptyList); @@ -341,13 +351,15 @@ private Optional insertEvent(EventCreationRequest request, Principal user }) .map(pair -> new ExtensionMetadataValue(pair.getRight().get().getId(), pair.getLeft().getValue())) .toList(); - extensionService.bulkUpdateEventSettings(organization, e, values); + extensionService.bulkUpdateEventSettings(organization, event, values); }); } - - }); - return event; + return Optional.of(event.getShortName()); + } catch (Exception ex) { + log.error("Error while inserting event", ex); + return Optional.empty(); + } } private String fetchImage(String url) { diff --git a/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java b/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java index 095ea22965..017aa62c3c 100644 --- a/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java +++ b/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java @@ -94,9 +94,9 @@ public EventCreationRequest(@JsonProperty("title") String title, } public EventModification toEventModification(Organization organization, UnaryOperator slugGenerator, String imageRef) { - String slug = this.slug; - if(StringUtils.isBlank(slug)) { - slug = slugGenerator.apply(title); + String eventSlug = this.slug; + if(StringUtils.isBlank(eventSlug)) { + eventSlug = slugGenerator.apply(title); } int locales = description.stream() @@ -114,7 +114,7 @@ public EventModification toEventModification(Organization organization, UnaryOpe StringUtils.trimToNull(privacyPolicyUrl), null, imageRef, - slug, + eventSlug, title, organization.getId(), location.getFullAddress(), @@ -124,13 +124,13 @@ public EventModification toEventModification(Organization organization, UnaryOpe description.stream().collect(Collectors.toMap(DescriptionRequest::getLang,DescriptionRequest::getBody)), new DateTimeModification(startDate.toLocalDate(),startDate.toLocalTime()), new DateTimeModification(endDate.toLocalDate(),endDate.toLocalTime()), - tickets.freeOfCharge ? BigDecimal.ZERO : tickets.categories.stream().map(x -> x.price).max(BigDecimal::compareTo).orElse(BigDecimal.ONE).max(BigDecimal.ONE), + Boolean.TRUE.equals(tickets.freeOfCharge) ? BigDecimal.ZERO : tickets.categories.stream().map(x -> x.price).max(BigDecimal::compareTo).orElse(BigDecimal.ONE).max(BigDecimal.ONE), tickets.currency, tickets.max, tickets.taxPercentage, tickets.taxIncludedInPrice, tickets.paymentMethods, - tickets.categories.stream().map(CategoryRequest::toTicketCategoryModification).collect(Collectors.toList()), + getTicketCategoryModificationList(), tickets.freeOfCharge, new LocationDescriptor(timezone, location.getCoordinate().getLatitude(), location.getCoordinate().getLongitude(), null), locales, @@ -141,6 +141,14 @@ public EventModification toEventModification(Organization organization, UnaryOpe ); } + private List getTicketCategoryModificationList() { + var result = new ArrayList(); + for (int c = 0; c < tickets.categories.size(); c++) { + result.add(tickets.categories.get(c).toNewTicketCategoryModification(c + 1 )); + } + return List.copyOf(result); + } + private static T first(T value,T other) { return Optional.ofNullable(value).orElse(other); } @@ -183,7 +191,7 @@ public EventModification toEventModificationUpdate(EventWithAdditionalInfo origi tickets != null ? first(tickets.taxPercentage,original.getVat()) : original.getVat(), tickets != null ? first(tickets.taxIncludedInPrice,original.isVatIncluded()) : original.isVatIncluded(), tickets != null ? first(tickets.paymentMethods, original.getAllowedPaymentProxies()) : original.getAllowedPaymentProxies(), - tickets != null && tickets.categories != null ? tickets.categories.stream().map(tc -> tc.toTicketCategoryModification(findCategoryId(original, tc))).collect(Collectors.toList()) : null, + tickets != null && tickets.categories != null ? createFromExistingCategories(original) : null, tickets != null ? first(tickets.freeOfCharge,original.isFreeOfCharge()) : original.isFreeOfCharge(), null, locales, @@ -194,12 +202,28 @@ public EventModification toEventModificationUpdate(EventWithAdditionalInfo origi ); } - private static Integer findCategoryId(EventWithAdditionalInfo event, CategoryRequest categoryRequest) { - return event.getTicketCategories().stream() - .filter(tc -> tc.getName().equals(categoryRequest.getName())) - .map(TicketCategoryWithAdditionalInfo::getId) - .findFirst() - .orElse(null); + private List createFromExistingCategories(EventWithAdditionalInfo event) { + var result = new ArrayList(tickets.categories.size()); + for(int c = 0; c < tickets.categories.size(); c++) { + var categoryRequest = tickets.categories.get(c); + var existing = findExistingCategory(event.getTicketCategories(), categoryRequest.getName(), categoryRequest.getId()); + if (existing.isPresent()) { + var category = existing.get(); + result.add(categoryRequest.toExistingTicketCategoryModification(category.getId(), category.getOrdinal())); + } else { + result.add(categoryRequest.toNewTicketCategoryModification(c + 1)); + } + } + return List.copyOf(result); + } + + public static Optional findExistingCategory(List categories, + String name, + Integer id) { + return categories.stream() + // if specified, ID takes precedence over name + .filter(oc -> id != null ? id == oc.getId() : oc.getName().equals(name)) + .findFirst(); } @@ -272,6 +296,7 @@ public CoordinateRequest(@JsonProperty("latitude") String latitude, @JsonPropert @Getter public static class CategoryRequest { + private final Integer id; private final String name; private final List description; private final Integer maxTickets; @@ -285,7 +310,8 @@ public static class CategoryRequest { private final TicketCategory.TicketAccessType ticketAccessType; @JsonCreator - public CategoryRequest(@JsonProperty("name") String name, + public CategoryRequest(@JsonProperty("id") Integer id, + @JsonProperty("name") String name, @JsonProperty("description") List description, @JsonProperty("maxTickets") Integer maxTickets, @JsonProperty("accessRestricted") boolean accessRestricted, @@ -296,6 +322,7 @@ public CategoryRequest(@JsonProperty("name") String name, @JsonProperty("customValidity") CustomTicketValidityRequest customValidity, @JsonProperty("groupLink") GroupLinkRequest groupLink, @JsonProperty("ticketAccessType") TicketCategory.TicketAccessType ticketAccessType) { + this.id = id; this.name = name; this.description = description; this.maxTickets = maxTickets; @@ -309,11 +336,11 @@ public CategoryRequest(@JsonProperty("name") String name, this.ticketAccessType = ticketAccessType; } - TicketCategoryModification toTicketCategoryModification() { - return toTicketCategoryModification(null); + TicketCategoryModification toNewTicketCategoryModification(int ordinal) { + return toExistingTicketCategoryModification(null, ordinal); } - TicketCategoryModification toTicketCategoryModification(Integer categoryId) { + TicketCategoryModification toExistingTicketCategoryModification(Integer categoryId, int ordinal) { int capacity = Optional.ofNullable(maxTickets).orElse(0); Optional customValidityOpt = Optional.ofNullable(customValidity); @@ -335,7 +362,7 @@ TicketCategoryModification toTicketCategoryModification(Integer categoryId) { customValidityOpt.flatMap(x -> Optional.ofNullable(x.checkInTo)).map(x -> new DateTimeModification(x.toLocalDate(),x.toLocalTime())).orElse(null), customValidityOpt.flatMap(x -> Optional.ofNullable(x.validityStart)).map(x -> new DateTimeModification(x.toLocalDate(),x.toLocalTime())).orElse(null), customValidityOpt.flatMap(x -> Optional.ofNullable(x.validityEnd)).map(x -> new DateTimeModification(x.toLocalDate(),x.toLocalTime())).orElse(null), - 0, + ordinal, null, null, AlfioMetadata.empty()); @@ -455,9 +482,9 @@ private EventModification.AdditionalField toAdditionalField(int ordinal) { String code = type != null ? type.code : AdditionalInfoType.GENERIC_TEXT.code; Integer minLength = contentLength != null ? contentLength.min : null; Integer maxLength = contentLength != null ? contentLength.max : null; - List restrictedValues = null; + List cleanRestrictedValues = null; if(!isEmpty(this.restrictedValues)) { - restrictedValues = this.restrictedValues.stream().map(rv -> new EventModification.RestrictedValue(rv.value, rv.enabled)).collect(Collectors.toList()); + cleanRestrictedValues = this.restrictedValues.stream().map(rv -> new EventModification.RestrictedValue(rv.value, rv.enabled)).toList(); } return new EventModification.AdditionalField( @@ -469,45 +496,45 @@ private EventModification.AdditionalField toAdditionalField(int ordinal) { false, minLength, maxLength, - restrictedValues, + cleanRestrictedValues, toDescriptionMap(orEmpty(label), orEmpty(placeholder), orEmpty(this.restrictedValues)), null,//TODO: linkedAdditionalService null);//TODO: linkedCategoryIds } + + private static Map toDescriptionMap(List label, + List placeholder, + List restrictedValues) { + Map labelsByLang = label.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); + Map placeholdersByLang = placeholder.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); + Map>> valuesByLang = restrictedValues.stream() + .flatMap(rv -> rv.descriptions.stream().map(rvd -> Triple.of(rvd.lang, rv.value, rvd.body))) + .collect(Collectors.groupingBy(Triple::getLeft)); + + + Set keys = new HashSet<>(labelsByLang.keySet()); + keys.addAll(placeholdersByLang.keySet()); + keys.addAll(valuesByLang.keySet()); + + return keys.stream() + .map(lang -> { + Map rvsMap = valuesByLang.getOrDefault(lang, emptyList()).stream().collect(Collectors.toMap(Triple::getMiddle, Triple::getRight)); + return Pair.of(lang, new EventModification.Description(labelsByLang.get(lang), placeholdersByLang.get(lang), rvsMap)); + }).collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); + } } private static List orEmpty(List input) { return isEmpty(input) ? emptyList() : input; } - private static Map toDescriptionMap(List label, - List placeholder, - List restrictedValues) { - Map labelsByLang = label.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); - Map placeholdersByLang = placeholder.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); - Map>> valuesByLang = restrictedValues.stream() - .flatMap(rv -> rv.descriptions.stream().map(rvd -> Triple.of(rvd.lang, rv.value, rvd.body))) - .collect(Collectors.groupingBy(Triple::getLeft)); - - - Set keys = new HashSet<>(labelsByLang.keySet()); - keys.addAll(placeholdersByLang.keySet()); - keys.addAll(valuesByLang.keySet()); - - return keys.stream() - .map(lang -> { - Map rvsMap = valuesByLang.getOrDefault(lang, emptyList()).stream().collect(Collectors.toMap(Triple::getMiddle, Triple::getRight)); - return Pair.of(lang, new EventModification.Description(labelsByLang.get(lang), placeholdersByLang.get(lang), rvsMap)); - }).collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); - } - private static List toAdditionalFields(List additionalInfoRequests) { if(isEmpty(additionalInfoRequests)) { return emptyList(); } AtomicInteger counter = new AtomicInteger(1); - return additionalInfoRequests.stream().map(air -> air.toAdditionalField(counter.getAndIncrement())).collect(Collectors.toList()); + return additionalInfoRequests.stream().map(air -> air.toAdditionalField(counter.getAndIncrement())).toList(); } @Getter diff --git a/src/test/java/alfio/controller/api/v1/EventApiV1IntegrationTest.java b/src/test/java/alfio/controller/api/v1/EventApiV1IntegrationTest.java index 1fe8f364c8..edbaa7a575 100644 --- a/src/test/java/alfio/controller/api/v1/EventApiV1IntegrationTest.java +++ b/src/test/java/alfio/controller/api/v1/EventApiV1IntegrationTest.java @@ -25,6 +25,7 @@ import alfio.manager.user.UserManager; import alfio.model.Event; import alfio.model.TicketCategory; +import alfio.model.TicketCategoryWithAdditionalInfo; import alfio.model.api.v1.admin.EventCreationRequest; import alfio.model.modification.OrganizationModification; import alfio.model.transaction.PaymentProxy; @@ -36,6 +37,7 @@ import alfio.repository.user.OrganizationRepository; import alfio.test.util.IntegrationTestUtil; import alfio.util.BaseIntegrationTest; +import alfio.util.ClockProvider; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,6 +56,7 @@ import java.util.List; import java.util.UUID; +import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.*; @@ -92,7 +95,7 @@ public static void initEnv() { private Organization organization; private Principal mockPrincipal; - private String shortName = "test"; + private final String slug = "test"; @BeforeEach public void ensureConfiguration() { @@ -123,8 +126,8 @@ static EventCreationRequest creationRequest(String shortName) { new EventCreationRequest.CoordinateRequest("45.5","9.00") ), "Europe/Zurich", - LocalDateTime.of(2020,1,10,12,0), - LocalDateTime.of(2020,1,10,18,0), + LocalDateTime.now(ClockProvider.clock()).plusDays(30), + LocalDateTime.now(ClockProvider.clock()).plusDays(30).plusHours(2), "https://alf.io", "https://alf.io", "https://alf.io", @@ -138,6 +141,7 @@ static EventCreationRequest creationRequest(String shortName) { Arrays.asList(PaymentProxy.OFFLINE,PaymentProxy.STRIPE), Collections.singletonList( new EventCreationRequest.CategoryRequest( + null, // forces new category "standard", Collections.singletonList(new EventCreationRequest.DescriptionRequest("en", "desc")), 10, @@ -164,14 +168,11 @@ static EventCreationRequest creationRequest(String shortName) { @Test void createTest() { - EventCreationRequest eventCreationRequest = creationRequest(shortName); + EventCreationRequest eventCreationRequest = creationRequest(slug); - String shortName = controller.create(eventCreationRequest,mockPrincipal).getBody(); - Event event = eventManager.getSingleEvent(shortName,username); + String slug = controller.create(eventCreationRequest,mockPrincipal).getBody(); + Event event = eventManager.getSingleEvent(slug,username); List tickets = ticketCategoryRepository.findAllTicketCategories(event.getId()); - - - assertEquals(eventCreationRequest.getTitle(),event.getDisplayName()); assertEquals(eventCreationRequest.getSlug(),event.getShortName()); assertEquals(eventCreationRequest.getTickets().getCurrency(),event.getCurrency()); @@ -183,39 +184,159 @@ void createTest() { List requestCategories = eventCreationRequest.getTickets().getCategories().stream().filter((rt) -> rt.getName().equals(t.getName())).toList(); assertEquals(1,requestCategories.size()); requestCategories.forEach((rtc) -> { + assertNotEquals(0, t.getOrdinal()); assertEquals(t.getMaxTickets(), rtc.getMaxTickets().intValue()); assertEquals(0, t.getPrice().compareTo(rtc.getPrice())); } ); } ); + } + @Test + void stats() { + controller.create(creationRequest(slug), mockPrincipal); + var statsResponse = controller.stats(slug, mockPrincipal); + assertTrue(statsResponse.getStatusCode().is2xxSuccessful()); + var stats = requireNonNull(statsResponse.getBody()); + int lastOrdinal = -1; + for (TicketCategoryWithAdditionalInfo ticketCategory : stats.getTicketCategories()) { + assertTrue(ticketCategory.getOrdinal() > 0); + assertTrue(ticketCategory.getOrdinal() > lastOrdinal); + lastOrdinal = ticketCategory.getOrdinal(); + } } @Test void updateTest() { - controller.create(creationRequest(shortName),mockPrincipal); - - + controller.create(creationRequest(slug), mockPrincipal); String newTitle = "new title"; EventCreationRequest updateRequest = new EventCreationRequest(newTitle,null,null,null, null,null,null,null,null,null, null,null, new EventCreationRequest.TicketRequest(null,10,null,null,null,null,null,null), null, null ); - controller.update(shortName,updateRequest,mockPrincipal); - Event event = eventManager.getSingleEvent(shortName,username); + controller.update(slug, updateRequest, mockPrincipal); + Event event = eventManager.getSingleEvent(slug,username); assertEquals(newTitle,event.getDisplayName()); + } + + @Test + void updateExistingCategoryUsingId() { + controller.create(creationRequest(slug), mockPrincipal); + var existing = requireNonNull(controller.stats(slug, mockPrincipal).getBody()); + var existingCategory = existing.getTicketCategories().get(0); + var categoriesRequest = List.of( + new EventCreationRequest.CategoryRequest( + existingCategory.getId(), + existingCategory.getName() + "_1", + List.of(new EventCreationRequest.DescriptionRequest("en", "desc")), + existingCategory.getMaxTickets(), + existingCategory.isAccessRestricted(), + existingCategory.getPrice(), + LocalDateTime.now(ClockProvider.clock()), + LocalDateTime.now(ClockProvider.clock()).plusHours(1), + existingCategory.getCode(), + null, + null, + existingCategory.getTicketAccessType() + ) + ); + var ticketRequest = new EventCreationRequest.TicketRequest(null,10,null,null,null,null, categoriesRequest,null); + EventCreationRequest updateRequest = new EventCreationRequest(null,null,null,null, null,null,null,null,null,null, null,null, + ticketRequest, null, null + ); + assertTrue(controller.update(slug, updateRequest, mockPrincipal).getStatusCode().is2xxSuccessful()); + var modifiedCategories = ticketCategoryRepository.findAllTicketCategories(existing.getId()); + assertEquals(1, modifiedCategories.size()); + assertEquals(existingCategory.getName() + "_1", modifiedCategories.get(0).getName()); + } + @Test + void updateExistingCategoryAndAddNewUsingId() { + controller.create(creationRequest(slug), mockPrincipal); + var existing = requireNonNull(controller.stats(slug, mockPrincipal).getBody()); + var existingCategory = existing.getTicketCategories().get(0); + var categoriesRequest = List.of( + new EventCreationRequest.CategoryRequest( + existingCategory.getId(), + existingCategory.getName() + "_1", + List.of(new EventCreationRequest.DescriptionRequest("en", "desc")), + existingCategory.getMaxTickets() - 5, + existingCategory.isAccessRestricted(), + existingCategory.getPrice(), + LocalDateTime.now(ClockProvider.clock()), + LocalDateTime.now(ClockProvider.clock()).plusHours(1), + existingCategory.getCode(), + null, + null, + existingCategory.getTicketAccessType() + ), + new EventCreationRequest.CategoryRequest( + null, + existingCategory.getName() + "_2", + List.of(new EventCreationRequest.DescriptionRequest("en", "desc")), + existingCategory.getMaxTickets() - 5, + existingCategory.isAccessRestricted(), + existingCategory.getPrice(), + LocalDateTime.now(ClockProvider.clock()), + LocalDateTime.now(ClockProvider.clock()).plusHours(1), + existingCategory.getCode(), + null, + null, + existingCategory.getTicketAccessType() + ) + ); + var ticketRequest = new EventCreationRequest.TicketRequest(null,10,null,null,null,null, categoriesRequest,null); + EventCreationRequest updateRequest = new EventCreationRequest(null,null,null,null, null,null,null,null,null,null, null,null, + ticketRequest, null, null + ); + assertTrue(controller.update(slug, updateRequest, mockPrincipal).getStatusCode().is2xxSuccessful()); + var modifiedCategories = ticketCategoryRepository.findAllTicketCategories(existing.getId()); + assertEquals(2, modifiedCategories.size()); + assertEquals(existingCategory.getName() + "_1", modifiedCategories.get(0).getName()); + assertEquals(existingCategory.getOrdinal(), modifiedCategories.get(0).getOrdinal()); + assertEquals(existingCategory.getName() + "_2", modifiedCategories.get(1).getName()); + assertEquals(existingCategory.getOrdinal() + 1, modifiedCategories.get(1).getOrdinal()); + } + + @Test + void updateExistingCategoryUsingName() { + controller.create(creationRequest(slug), mockPrincipal); + var existing = requireNonNull(controller.stats(slug, mockPrincipal).getBody()); + var existingCategory = existing.getTicketCategories().get(0); + var categoriesRequest = List.of( + new EventCreationRequest.CategoryRequest(null, + existingCategory.getName(), + List.of(new EventCreationRequest.DescriptionRequest("en", "desc")), + existingCategory.getMaxTickets() - 1, + existingCategory.isAccessRestricted(), + existingCategory.getPrice(), + LocalDateTime.now(ClockProvider.clock()), + LocalDateTime.now(ClockProvider.clock()).plusHours(1), + existingCategory.getCode(), + null, + null, + existingCategory.getTicketAccessType() + ) + ); + var ticketRequest = new EventCreationRequest.TicketRequest(null,10,null,null,null,null, categoriesRequest,null); + EventCreationRequest updateRequest = new EventCreationRequest(null,null,null,null, null,null,null,null,null,null, null,null, + ticketRequest, null, null + ); + assertTrue(controller.update(slug, updateRequest, mockPrincipal).getStatusCode().is2xxSuccessful()); + var modifiedCategories = ticketCategoryRepository.findAllTicketCategories(existing.getId()); + assertEquals(1, modifiedCategories.size()); + assertEquals(existingCategory.getMaxTickets() - 1, modifiedCategories.get(0).getMaxTickets()); } @Test void retrieveLinkedSubscriptions() { - controller.create(creationRequest(shortName),mockPrincipal); - var response = controller.getLinkedSubscriptions(shortName, mockPrincipal); + controller.create(creationRequest(slug),mockPrincipal); + var response = controller.getLinkedSubscriptions(slug, mockPrincipal); assertTrue(response.getStatusCode().is2xxSuccessful()); var linkedSubscriptions = response.getBody(); assertNotNull(linkedSubscriptions); assertTrue(linkedSubscriptions.getSubscriptions().isEmpty()); - assertEquals(shortName, linkedSubscriptions.getEventSlug()); + assertEquals(slug, linkedSubscriptions.getEventSlug()); } From 07ed478681dabbc059513d8b389793704ccdf8dc Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sun, 5 Feb 2023 18:00:25 +0100 Subject: [PATCH 147/218] update API descriptor.json --- src/test/resources/api/descriptor.json | 184 +++++++++++++------------ 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/src/test/resources/api/descriptor.json b/src/test/resources/api/descriptor.json index a99166a4dd..9b8e1ac60d 100644 --- a/src/test/resources/api/descriptor.json +++ b/src/test/resources/api/descriptor.json @@ -25470,15 +25470,15 @@ "location" : { "type" : "string" }, + "description" : { + "type" : "string" + }, "arguments" : { "type" : "array", "items" : { "type" : "object" } }, - "description" : { - "type" : "string" - }, "code" : { "type" : "string" } @@ -25879,6 +25879,10 @@ "type" : "integer", "format" : "int32" }, + "ticketAmount" : { + "type" : "integer", + "format" : "int32" + }, "singleTicketOrder" : { "type" : "boolean" }, @@ -25896,10 +25900,6 @@ }, "priceBeforeTaxes" : { "type" : "string" - }, - "ticketAmount" : { - "type" : "integer", - "format" : "int32" } } }, @@ -26154,12 +26154,12 @@ "taxPercentage" : { "type" : "string" }, - "descriptionForPayment" : { - "type" : "string" - }, "discount" : { "type" : "boolean" }, + "descriptionForPayment" : { + "type" : "string" + }, "taxDetail" : { "type" : "boolean" } @@ -26593,15 +26593,9 @@ "type" : "integer", "format" : "int32" }, - "vatStatus" : { + "paymentMethod" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" + "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] }, "hasInvoiceNumber" : { "type" : "boolean" @@ -26609,22 +26603,11 @@ "invoiceNumber" : { "type" : "string" }, - "paymentMethod" : { - "type" : "string", - "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] - }, - "srcPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "finalPrice" : { - "type" : "number" - }, - "vat" : { - "type" : "number" + "firstName" : { + "type" : "string" }, - "appliedDiscount" : { - "type" : "number" + "lastName" : { + "type" : "string" }, "finalPriceCts" : { "type" : "integer", @@ -26647,6 +26630,23 @@ "invoiceRequested" : { "type" : "boolean" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, + "srcPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "finalPrice" : { + "type" : "number" + }, + "vat" : { + "type" : "number" + }, + "appliedDiscount" : { + "type" : "number" + }, "pendingOfflinePayment" : { "type" : "boolean" }, @@ -28126,6 +28126,10 @@ "CategoryRequest" : { "type" : "object", "properties" : { + "id" : { + "type" : "integer", + "format" : "int32" + }, "name" : { "type" : "string" }, @@ -28469,10 +28473,6 @@ "assigned" : { "type" : "boolean" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "eventId" : { "type" : "integer", "format" : "int32" @@ -28487,10 +28487,6 @@ "type" : "string", "format" : "uuid" }, - "srcPriceCts" : { - "type" : "integer", - "format" : "int32" - }, "finalPriceCts" : { "type" : "integer", "format" : "int32" @@ -28503,6 +28499,14 @@ "type" : "integer", "format" : "int32" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, + "srcPriceCts" : { + "type" : "integer", + "format" : "int32" + }, "email" : { "type" : "string" }, @@ -29021,12 +29025,12 @@ "type" : "string", "format" : "date-time" }, - "overlap" : { - "type" : "boolean" - }, "instant" : { "type" : "string", "format" : "date-time" + }, + "overlap" : { + "type" : "boolean" } } } @@ -29792,10 +29796,6 @@ "assigned" : { "type" : "boolean" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "eventId" : { "type" : "integer", "format" : "int32" @@ -29810,10 +29810,6 @@ "type" : "string", "format" : "uuid" }, - "srcPriceCts" : { - "type" : "integer", - "format" : "int32" - }, "finalPriceCts" : { "type" : "integer", "format" : "int32" @@ -29826,6 +29822,14 @@ "type" : "integer", "format" : "int32" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, + "srcPriceCts" : { + "type" : "integer", + "format" : "int32" + }, "email" : { "type" : "string" }, @@ -30175,12 +30179,12 @@ "type" : "string", "format" : "date-time" }, - "overlap" : { - "type" : "boolean" - }, "instant" : { "type" : "string", "format" : "date-time" + }, + "overlap" : { + "type" : "boolean" } } } @@ -31718,15 +31722,15 @@ "displayName" : { "type" : "string" }, + "publicIdentifier" : { + "type" : "string" + }, "contentLanguages" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ContentLanguage" } }, - "publicIdentifier" : { - "type" : "string" - }, "allowedPaymentProxies" : { "type" : "array", "items" : { @@ -31872,10 +31876,6 @@ "transaction" : { "$ref" : "#/components/schemas/Transaction" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "eventId" : { "type" : "integer", "format" : "int32" @@ -31890,13 +31890,6 @@ "type" : "string", "format" : "uuid" }, - "srcPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "finalPrice" : { - "type" : "number" - }, "finalPriceCts" : { "type" : "integer", "format" : "int32" @@ -31909,6 +31902,17 @@ "type" : "integer", "format" : "int32" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, + "srcPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "finalPrice" : { + "type" : "number" + }, "email" : { "type" : "string" }, @@ -31947,16 +31951,16 @@ "stuck" : { "type" : "boolean" }, + "transactionTimestamp" : { + "type" : "string", + "format" : "date-time" + }, "paid" : { "type" : "boolean" }, "pending" : { "type" : "boolean" }, - "transactionTimestamp" : { - "type" : "string", - "format" : "date-time" - }, "netPrice" : { "type" : "number" }, @@ -32117,10 +32121,6 @@ "assigned" : { "type" : "boolean" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "eventId" : { "type" : "integer", "format" : "int32" @@ -32135,10 +32135,6 @@ "type" : "string", "format" : "uuid" }, - "srcPriceCts" : { - "type" : "integer", - "format" : "int32" - }, "finalPriceCts" : { "type" : "integer", "format" : "int32" @@ -32151,6 +32147,14 @@ "type" : "integer", "format" : "int32" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, + "srcPriceCts" : { + "type" : "integer", + "format" : "int32" + }, "email" : { "type" : "string" }, @@ -33293,6 +33297,9 @@ "expired" : { "type" : "boolean" }, + "formattedEnd" : { + "type" : "string" + }, "notSoldTickets" : { "type" : "integer", "format" : "int32" @@ -33313,9 +33320,6 @@ "type" : "integer", "format" : "int32" }, - "formattedEnd" : { - "type" : "string" - }, "warningNeeded" : { "type" : "boolean" }, @@ -33831,18 +33835,18 @@ "type" : "string" } }, - "contentLanguages" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ContentLanguage" - } - }, "publicIdentifier" : { "type" : "string" }, "free" : { "type" : "boolean" }, + "contentLanguages" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/ContentLanguage" + } + }, "privacyPolicyLinkOrNull" : { "type" : "string" }, From 9d2945a93813255550ea1ed87d4ad020eadb2b15 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sun, 5 Feb 2023 18:15:25 +0100 Subject: [PATCH 148/218] add docs for SUBSCRIPTION_ASSIGNED_GENERATE_METADATA --- .../Extensions/reference/subscription.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 website/content/en/docs/Reference/Extensions/reference/subscription.md diff --git a/website/content/en/docs/Reference/Extensions/reference/subscription.md b/website/content/en/docs/Reference/Extensions/reference/subscription.md new file mode 100644 index 0000000000..ae98ba3220 --- /dev/null +++ b/website/content/en/docs/Reference/Extensions/reference/subscription.md @@ -0,0 +1,43 @@ +--- +title: "Subscription" +linkTitle: "Subscription" +weight: 4 +date: 2023-02-05 +description: > + Compatible Application Events for the "Subscription" entity +--- + +### Customize subscription metadata +`SUBSCRIPTION_ASSIGNED_GENERATE_METADATA` + +Fired **synchronously** before marking a subscription as "acquired". The purpose of this extension is to allow metadata customization. + +A result of type [`SubscriptionMetadata`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/metadata/SubscriptionMetadata.java) is expected. Return `null` if you don't need to modify the current metadata. +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
VariableTypeAbout
`subscription`[`Subscription`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/Subscription.java)Details about the subscription to be acquired
`subscriptionDescriptor`[`SubscriptionDescriptor`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/SubscriptionDescriptor.java)Subscription configuration (template)
`metadata`[`SubscriptionMetadata`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/metadata/SubscriptionMetadata.java)Existing metadata for subscription.
+
\ No newline at end of file From a0cea27739bbf4c40d8eb3975abc83ca8d88393c Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Tue, 7 Feb 2023 18:40:08 +0100 Subject: [PATCH 149/218] fix broken links --- .../en/docs/Reference/Extensions/reference/subscription.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/content/en/docs/Reference/Extensions/reference/subscription.md b/website/content/en/docs/Reference/Extensions/reference/subscription.md index ae98ba3220..5f70955aa2 100644 --- a/website/content/en/docs/Reference/Extensions/reference/subscription.md +++ b/website/content/en/docs/Reference/Extensions/reference/subscription.md @@ -25,12 +25,12 @@ A result of type [`SubscriptionMetadata`](https://github.com/alfio-event/alf.io/ `subscription` - [`Subscription`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/Subscription.java) + [`Subscription`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/subscription/Subscription.java) Details about the subscription to be acquired `subscriptionDescriptor` - [`SubscriptionDescriptor`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/SubscriptionDescriptor.java) + [`SubscriptionDescriptor`](https://github.com/alfio-event/alf.io/blob/master/src/main/java/alfio/model/subscription/SubscriptionDescriptor.java) Subscription configuration (template) From f3415c50b1c034e2363818fe8aa904b277053bc7 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Fri, 10 Feb 2023 17:05:40 +0100 Subject: [PATCH 150/218] Custom vat application (#1193) - cherry-picked from 4f7f5ca62bbfd0969876332dab359741ac7d69e0 --- .../v2/user/ReservationApiV2Controller.java | 14 +- .../java/alfio/manager/ExtensionManager.java | 30 ++- .../alfio/manager/ReverseChargeManager.java | 122 +++++++-- .../manager/TicketReservationManager.java | 18 +- .../support/extension/ExtensionEvent.java | 1 + .../system/ReservationPriceCalculator.java | 2 +- src/main/java/alfio/model/Audit.java | 1 + src/main/java/alfio/model/OrderSummary.java | 3 +- src/main/java/alfio/model/PriceContainer.java | 12 +- src/main/java/alfio/model/SummaryRow.java | 3 +- src/main/java/alfio/model/Ticket.java | 27 ++ src/main/java/alfio/model/TicketInfo.java | 8 +- .../model/decorator/TicketPriceContainer.java | 4 +- .../model/extension/CustomTaxPolicy.java | 78 ++++++ .../alfio/repository/TicketRepository.java | 20 +- .../java/alfio/util/TemplateResource.java | 2 +- ...V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql | 19 ++ .../reservation/BaseReservationFlowTest.java | 25 +- .../CustomTaxPolicyIntegrationTest.java | 253 ++++++++++++++++++ .../StripeReservationFlowIntegrationTest.java | 3 +- .../alfio/manager/ExtensionManagerTest.java | 2 +- .../alfio/test/util/IntegrationTestUtil.java | 21 +- .../resources/custom-tax-policy-extension.js | 56 ++++ 23 files changed, 655 insertions(+), 69 deletions(-) create mode 100644 src/main/java/alfio/model/extension/CustomTaxPolicy.java create mode 100644 src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql create mode 100644 src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java create mode 100644 src/test/resources/custom-tax-policy-extension.js diff --git a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java index f22254d225..41da144c66 100644 --- a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java @@ -16,13 +16,13 @@ */ package alfio.controller.api.v2.user; +import alfio.controller.api.support.BookingInfoTicketLoader; import alfio.controller.api.support.TicketHelper; import alfio.controller.api.v2.model.PaymentProxyWithParameters; import alfio.controller.api.v2.model.ReservationInfo; import alfio.controller.api.v2.model.ReservationInfo.TicketsByTicketCategory; import alfio.controller.api.v2.model.ReservationPaymentResult; import alfio.controller.api.v2.model.ReservationStatusInfo; -import alfio.controller.api.support.BookingInfoTicketLoader; import alfio.controller.api.v2.user.support.ReservationAccessDenied; import alfio.controller.form.ContactAndTicketsForm; import alfio.controller.form.PaymentForm; @@ -434,7 +434,17 @@ public ResponseEntity> validateToOverview(@PathVariab ticketReservationRepository.resetVat(reservationId, contactAndTicketsForm.isInvoiceRequested(), purchaseContext.getVatStatus(), reservation.getSrcPriceCts(), reservationCost.priceWithVAT(), reservationCost.VAT(), Math.abs(reservationCost.discount()), reservation.getCurrencyCode()); - if(contactAndTicketsForm.isBusiness()) { + + var optionalCustomTaxPolicy = extensionManager.handleCustomTaxPolicy(purchaseContext, reservationId, contactAndTicketsForm, reservationCost); + if (optionalCustomTaxPolicy.isPresent()) { + log.debug("Custom tax policy returned for reservation {}. Applying it.", reservationId); + reverseChargeManager.applyCustomTaxPolicy( + purchaseContext, + optionalCustomTaxPolicy.get(), + reservationId, + contactAndTicketsForm, + bindingResult); + } else if(contactAndTicketsForm.isBusiness()) { reverseChargeManager.checkAndApplyVATRules(purchaseContext, reservationId, contactAndTicketsForm, bindingResult); } else if(reservationCost.priceWithVAT() > 0) { reverseChargeManager.resetVat(purchaseContext, reservationId); diff --git a/src/main/java/alfio/manager/ExtensionManager.java b/src/main/java/alfio/manager/ExtensionManager.java index cbeacab233..f0269234d7 100644 --- a/src/main/java/alfio/manager/ExtensionManager.java +++ b/src/main/java/alfio/manager/ExtensionManager.java @@ -18,6 +18,7 @@ package alfio.manager; import alfio.config.authentication.support.OpenIdAlfioAuthentication; +import alfio.controller.form.ContactAndTicketsForm; import alfio.extension.ExtensionService; import alfio.extension.exception.AlfioScriptingException; import alfio.manager.payment.PaymentSpecification; @@ -39,10 +40,7 @@ import alfio.model.user.Organization; import alfio.model.user.PublicUserProfile; import alfio.model.user.User; -import alfio.repository.EventRepository; -import alfio.repository.TicketRepository; -import alfio.repository.TicketReservationRepository; -import alfio.repository.TransactionRepository; +import alfio.repository.*; import alfio.util.ClockProvider; import alfio.util.EventUtil; import alfio.util.MonetaryUtil; @@ -58,6 +56,8 @@ import java.nio.file.Paths; import java.time.ZonedDateTime; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import static alfio.extension.ExtensionService.toPath; import static alfio.manager.support.extension.ExtensionEvent.*; @@ -86,6 +86,7 @@ public class ExtensionManager { private final TicketRepository ticketRepository; private final ConfigurationManager configurationManager; private final TransactionRepository transactionRepository; + private final TicketCategoryRepository ticketCategoryRepository; public ExtensionManager(ExtensionService extensionService, EventRepository eventRepository, @@ -551,4 +552,25 @@ public Optional handleSubscriptionAssignmentMetadata(Subsc context.put("subscriptionDescriptor", descriptor); return Optional.ofNullable(syncCall(ExtensionEvent.SUBSCRIPTION_ASSIGNED_GENERATE_METADATA, descriptor, context, SubscriptionMetadata.class, false)); } + + public Optional handleCustomTaxPolicy(PurchaseContext purchaseContext, + String reservationId, + ContactAndTicketsForm form, + TotalPrice reservationCost) { + if (!purchaseContext.ofType(PurchaseContext.PurchaseContextType.event) || !reservationCost.requiresPayment()) { + return Optional.empty(); + } + var event = (Event) purchaseContext; + var categoriesById = ticketCategoryRepository.findCategoriesInReservation(reservationId).stream() + .collect(Collectors.toMap(TicketCategory::getId, Function.identity())); + var ticketInfoById = ticketRepository.findBasicTicketInfoForReservation(event.getId(), reservationId).stream() + .collect(Collectors.toMap(TicketInfo::getTicketUuid, Function.identity())); + var context = new HashMap(); + context.put(EVENT, event); + context.put(RESERVATION_ID, reservationId); + context.put("reservationForm", form); + context.put("categoriesById", categoriesById); + context.put("ticketInfoByUuid", ticketInfoById); + return Optional.ofNullable(syncCall(CUSTOM_TAX_POLICY_APPLICATION, event, context, CustomTaxPolicy.class, false)); + } } diff --git a/src/main/java/alfio/manager/ReverseChargeManager.java b/src/main/java/alfio/manager/ReverseChargeManager.java index 799eba30bc..993c875356 100644 --- a/src/main/java/alfio/manager/ReverseChargeManager.java +++ b/src/main/java/alfio/manager/ReverseChargeManager.java @@ -17,10 +17,17 @@ package alfio.manager; import alfio.controller.form.ContactAndTicketsForm; +import alfio.controller.support.CustomBindingResult; import alfio.manager.system.ConfigurationManager; import alfio.manager.system.ReservationPriceCalculator; import alfio.model.*; +import alfio.model.decorator.TicketPriceContainer; +import alfio.model.extension.CustomTaxPolicy; import alfio.repository.*; +import alfio.util.MonetaryUtil; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Component; @@ -28,14 +35,14 @@ import org.springframework.validation.ValidationUtils; import java.math.BigDecimal; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import static alfio.model.Audit.EntityType.RESERVATION; import static alfio.model.PriceContainer.VatStatus.*; -import static alfio.model.PriceContainer.VatStatus.NOT_INCLUDED_NOT_CHARGED; import static alfio.model.system.ConfigurationKeys.*; import static alfio.util.MonetaryUtil.unitToCents; import static java.util.stream.Collectors.toMap; @@ -44,6 +51,7 @@ @Component public class ReverseChargeManager { + private static final Logger log = LoggerFactory.getLogger(ReverseChargeManager.class); private final PromoCodeDiscountRepository promoCodeDiscountRepository; private final AdditionalServiceItemRepository additionalServiceItemRepository; private final AdditionalServiceRepository additionalServiceRepository; @@ -55,6 +63,7 @@ public class ReverseChargeManager { private final TicketReservationManager ticketReservationManager; private final TicketRepository ticketRepository; private final SubscriptionRepository subscriptionRepository; + private final AuditingRepository auditingRepository; public ReverseChargeManager(PromoCodeDiscountRepository promoCodeDiscountRepository, AdditionalServiceItemRepository additionalServiceItemRepository, @@ -66,7 +75,8 @@ public ReverseChargeManager(PromoCodeDiscountRepository promoCodeDiscountReposit EuVatChecker vatChecker, TicketReservationManager ticketReservationManager, TicketRepository ticketRepository, - SubscriptionRepository subscriptionRepository) { + SubscriptionRepository subscriptionRepository, + AuditingRepository auditingRepository) { this.promoCodeDiscountRepository = promoCodeDiscountRepository; this.additionalServiceItemRepository = additionalServiceItemRepository; this.additionalServiceRepository = additionalServiceRepository; @@ -78,6 +88,7 @@ public ReverseChargeManager(PromoCodeDiscountRepository promoCodeDiscountReposit this.ticketReservationManager = ticketReservationManager; this.ticketRepository = ticketRepository; this.subscriptionRepository = subscriptionRepository; + this.auditingRepository = auditingRepository; } @@ -131,7 +142,7 @@ public void checkAndApplyVATRules(PurchaseContext purchaseContext, var currencyCode = reservation.getCurrencyCode(); PriceContainer.VatStatus vatStatus = determineVatStatus(purchaseContext.getVatStatus(), vatValidation.isVatExempt()); // standard case: Reverse Charge is applied to the entire reservation - var discount = reservation.getPromoCodeDiscountId() != null ? promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()) : null; + var discount = getDiscountOrNull(reservation); if(!isEvent || (reverseChargeOnline && reverseChargeInPerson)) { if(isEvent) { var event = purchaseContext.event().orElseThrow(); @@ -172,11 +183,63 @@ public void checkAndApplyVATRules(PurchaseContext purchaseContext, } } + private PromoCodeDiscount getDiscountOrNull(TicketReservation reservation) { + if (reservation.getPromoCodeDiscountId() != null) { + return promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()); + } + return null; + } + + public void applyCustomTaxPolicy(PurchaseContext purchaseContext, + CustomTaxPolicy customTaxPolicy, + String reservationId, + ContactAndTicketsForm contactAndTicketsForm, + CustomBindingResult bindingResult) { + + if (!purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { + throw new IllegalStateException("Custom tax policy is only supported for events"); + } + + var event = (Event) purchaseContext; + // first, validate that categories in CustomTaxPolicy are actually present in the form + var reservation = ticketReservationManager.findById(reservationId).orElseThrow(); + var currencyCode = reservation.getCurrencyCode(); + var ticketsInReservation = ticketRepository.findTicketsInReservation(reservationId).stream() + .collect(toMap(Ticket::getUuid, Function.identity())); + var ticketIds = ticketsInReservation.keySet(); + if (customTaxPolicy.getTicketPolicies().stream().anyMatch(tp -> !ticketIds.contains(tp.getUuid()))) { + log.warn("Error in custom tax policy: some tickets are not included in reservation {}", reservationId); + bindingResult.reject("error.generic"); + } else { + // log the received policy to the auditing + auditingRepository.insert(reservationId, null, purchaseContext, Audit.EventType.VAT_CUSTOM_CONFIGURATION_APPLIED, new Date(), RESERVATION, reservationId, List.of(Map.of("policy", customTaxPolicy))); + var priceMapping = customTaxPolicy.getTicketPolicies().stream() + .map(tcp -> toTicketPriceContainer(ticketsInReservation.get(tcp.getUuid()), tcp, getDiscountOrNull(reservation), event)) + .collect(Collectors.toList()); + updateTicketPrices(priceMapping, currencyCode, event); + // update billing data for the reservation, using the original VatStatus from reservation + updateBillingData(reservationId, contactAndTicketsForm, purchaseContext, reservation.getVatCountryCode(), trimToNull(reservation.getVatNr()), reservation, reservation.getVatStatus()); + } + } + + private static TicketPriceContainer toTicketPriceContainer(Ticket ticket, + CustomTaxPolicy.TicketTaxPolicy categoryTaxPolicy, + PromoCodeDiscount discount, + Event event) { + return TicketPriceContainer.from( + ticket.withVatStatus(categoryTaxPolicy.getTaxPolicy()), + categoryTaxPolicy.getTaxPolicy(), + event.getVat(), + event.getVatStatus(), + discount + ); + } + public void resetVat(PurchaseContext purchaseContext, String reservationId) { if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { var reservation = ticketReservationRepository.findReservationById(reservationId); var categoriesList = ticketCategoryRepository.findCategoriesInReservation(reservationId); - var discount = reservation.getPromoCodeDiscountId() != null ? promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()) : null; + var discount = getDiscountOrNull(reservation); var event = purchaseContext.event().orElseThrow(); var priceContainers = mapPriceContainersByCategoryId(categoriesList, (a) -> true, @@ -208,23 +271,38 @@ private void updateTicketPricesByCategory(String reservationId, Event event, Map matchingCategories) { MapSqlParameterSource[] parameterSources = matchingCategories.entrySet().stream() - .map(entry -> { - var value = entry.getValue(); - return new MapSqlParameterSource() - .addValue("reservationId", reservationId) - .addValue("categoryId", entry.getKey()) - .addValue("eventId", event.getId()) - .addValue("srcPriceCts", value.getSrcPriceCts()) - .addValue("finalPriceCts", value.getFinalPriceCts()) - .addValue("vatCts", value.getVatCts()) - .addValue("discountCts", value.getDiscountCts()) - .addValue("currencyCode", currencyCode) - .addValue("vatStatus", vatStatus.name()); - } - ).toArray(MapSqlParameterSource[]::new); + .map(entry -> buildParameterSourceForPriceUpdate(entry.getValue(), event.getId(), entry.getKey(), currencyCode, vatStatus, + m -> m.addValue("reservationId", reservationId))) + .toArray(MapSqlParameterSource[]::new); jdbcTemplate.batchUpdate(ticketRepository.updateTicketPriceForCategoryInReservation(), parameterSources); } + private void updateTicketPrices(List ticketPrices, String currencyCode, Event event) { + MapSqlParameterSource[] parameterSources = ticketPrices.stream() + .map(entry -> buildParameterSourceForPriceUpdate(entry, event.getId(), entry.getCategoryId(), currencyCode, entry.getVatStatus(), + m -> m.addValue("uuid", entry.getUuid()))) + .toArray(MapSqlParameterSource[]::new); + var updateResult = jdbcTemplate.batchUpdate(ticketRepository.bulkUpdateTicketPrice(), parameterSources); + Validate.isTrue(Arrays.stream(updateResult).allMatch(i -> i == 1), "Error while updating ticket prices"); + } + + private static MapSqlParameterSource buildParameterSourceForPriceUpdate(PriceContainer value, + int eventId, + int categoryId, + String currencyCode, + PriceContainer.VatStatus vatStatus, + UnaryOperator modifier) { + return modifier.apply(new MapSqlParameterSource() + .addValue("categoryId", categoryId) + .addValue("eventId", eventId) + .addValue("srcPriceCts", value.getSrcPriceCts()) + .addValue("finalPriceCts", MonetaryUtil.unitToCents(value.getFinalPrice(), currencyCode)) + .addValue("vatCts", MonetaryUtil.unitToCents(value.getVAT(), currencyCode)) + .addValue("discountCts", MonetaryUtil.unitToCents(value.getAppliedDiscount(), currencyCode)) + .addValue("currencyCode", currencyCode) + .addValue("vatStatus", vatStatus.name())); + } + private Predicate findReverseChargeCategory(boolean reverseChargeInPerson, boolean reverseChargeOnline, Event.EventFormat eventFormat) { return tc -> { if (eventFormat == Event.EventFormat.HYBRID) { @@ -236,7 +314,7 @@ private Predicate findReverseChargeCategory(boolean reverseCharg } private void updateBillingData(String reservationId, ContactAndTicketsForm contactAndTicketsForm, PurchaseContext purchaseContext, String country, String vatNr, TicketReservation reservation, PriceContainer.VatStatus vatStatus) { - var discount = reservation.getPromoCodeDiscountId() != null ? promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()) : null; + var discount = getDiscountOrNull(reservation); var additionalServiceItems = additionalServiceItemRepository.findByReservationUuid(reservation.getId()); var tickets = ticketReservationManager.findTicketsInReservation(reservation.getId()); var additionalServices = purchaseContext.event().map(event -> additionalServiceRepository.loadAllForEvent(event.getId())).orElse(List.of()); diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 57a07e9a39..f8e0b36b92 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -1052,7 +1052,7 @@ void issueCreditNoteForRefund(PurchaseContext purchaseContext, TicketReservation var cost = new TotalPrice(priceContainer.getSrcPriceCts(), unitToCents(priceContainer.getVAT(), currencyCode), 0, 0, currencyCode); var orderSummary = new OrderSummary( cost, - List.of(new SummaryRow(summaryRowTitle, formattedAmount, formattedPriceBeforeVat, 1, formattedAmount, formattedPriceBeforeVat, unitToCents(refundAmount, currencyCode), SummaryType.TICKET, null)), + List.of(new SummaryRow(summaryRowTitle, formattedAmount, formattedPriceBeforeVat, 1, formattedAmount, formattedPriceBeforeVat, unitToCents(refundAmount, currencyCode), SummaryType.TICKET, null, priceContainer.getVatStatus())), false, formattedAmount, formatUnit(priceContainer.getVAT(), currencyCode), @@ -1743,8 +1743,8 @@ List extractSummary(VatStatus reservationVatStatus, final int ticketPriceCts = firstTicket.getSummarySrcPriceCts(); final int priceBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(firstTicket)); String categoryName = categoriesById.get(categoryWithTickets.getKey()).getName(); - summary.add(new SummaryRow(categoryName, formatCents(ticketPriceCts, currencyCode), formatCents(priceBeforeVat, currencyCode), categoryTickets.size(), formatCents(subTotal, currencyCode), formatCents(subTotalBeforeVat, currencyCode), subTotal, SummaryType.TICKET, null)); var ticketVatStatus = firstTicket.getVatStatus(); + summary.add(new SummaryRow(categoryName, formatCents(ticketPriceCts, currencyCode), formatCents(priceBeforeVat, currencyCode), categoryTickets.size(), formatCents(subTotal, currencyCode), formatCents(subTotalBeforeVat, currencyCode), subTotal, SummaryType.TICKET, null, ticketVatStatus)); if (VatStatus.isVatExempt(ticketVatStatus) && ticketVatStatus != reservationVatStatus) { summary.add(new SummaryRow(null, "", @@ -1754,7 +1754,7 @@ List extractSummary(VatStatus reservationVatStatus, formatCents(0, currencyCode, true), 0, SummaryType.TAX_DETAIL, - "0")); + "0", ticketVatStatus)); } } }); @@ -1770,7 +1770,7 @@ List extractSummary(VatStatus reservationVatStatus, AdditionalServiceItemPriceContainer first = prices.get(0); final int subtotal = prices.stream().mapToInt(AdditionalServiceItemPriceContainer::getSrcPriceCts).sum(); final int subtotalBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(prices); - return new SummaryRow(title.value(), formatCents(first.getSrcPriceCts(), currencyCode), formatCents(SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(first)), currencyCode), prices.size(), formatCents(subtotal, currencyCode), formatCents(subtotalBeforeVat, currencyCode), subtotal, SummaryType.ADDITIONAL_SERVICE, null); + return new SummaryRow(title.value(), formatCents(first.getSrcPriceCts(), currencyCode), formatCents(SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(first)), currencyCode), prices.size(), formatCents(subtotal, currencyCode), formatCents(subtotalBeforeVat, currencyCode), subtotal, SummaryType.ADDITIONAL_SERVICE, null, first.getVatStatus()); }).toList()); Optional.ofNullable(promoCodeDiscount).ifPresent(promo -> { @@ -1781,7 +1781,7 @@ List extractSummary(VatStatus reservationVatStatus, reservationCost.discountAppliedCount(), formatCents(reservationCost.discount(), currencyCode), formatCents(reservationCost.discount(), currencyCode), reservationCost.discount(), promo.isDynamic() ? SummaryType.DYNAMIC_DISCOUNT : SummaryType.PROMOTION_CODE, - null)); + null, reservationVatStatus)); }); // if(purchaseContext instanceof SubscriptionDescriptor subscriptionDescriptor) { @@ -1797,8 +1797,8 @@ List extractSummary(VatStatus reservationVatStatus, formatUnit(priceContainer.getNetPrice().multiply(new BigDecimal(subscriptionsToInclude.size())), currencyCode), priceContainer.getSummarySrcPriceCts(), SummaryType.SUBSCRIPTION, - null - )); + null, + reservationVatStatus)); } } else if(CollectionUtils.isNotEmpty(subscriptionsToInclude)) { log.trace("subscriptions to include is not empty"); @@ -1817,8 +1817,8 @@ List extractSummary(VatStatus reservationVatStatus, "-" + formatCents(priceBeforeVat, currencyCode), ticketPriceCts, SummaryType.APPLIED_SUBSCRIPTION, - null - )); + null, + reservationVatStatus)); }); } diff --git a/src/main/java/alfio/manager/support/extension/ExtensionEvent.java b/src/main/java/alfio/manager/support/extension/ExtensionEvent.java index 6718fd553c..c668fa83ef 100644 --- a/src/main/java/alfio/manager/support/extension/ExtensionEvent.java +++ b/src/main/java/alfio/manager/support/extension/ExtensionEvent.java @@ -29,6 +29,7 @@ public enum ExtensionEvent { CREDIT_NOTE_GENERATION, CREDIT_NOTE_GENERATED, TAX_ID_NUMBER_VALIDATION, + CUSTOM_TAX_POLICY_APPLICATION, RESERVATION_VALIDATION, EVENT_METADATA_UPDATE, // diff --git a/src/main/java/alfio/manager/system/ReservationPriceCalculator.java b/src/main/java/alfio/manager/system/ReservationPriceCalculator.java index d09ab79822..b2dafa26ef 100644 --- a/src/main/java/alfio/manager/system/ReservationPriceCalculator.java +++ b/src/main/java/alfio/manager/system/ReservationPriceCalculator.java @@ -135,7 +135,7 @@ public static ReservationPriceCalculator from(TicketReservation reservation, Pro } private int getTicketSrcPriceCts(Ticket t) { - if(t.getVatStatus() == VatStatus.INCLUDED_EXEMPT || t.getVatStatus() == VatStatus.NOT_INCLUDED_EXEMPT) { + if(VatStatus.isVatExempt(t.getVatStatus())) { return t.getSrcPriceCts() - Math.abs(t.getVatCts()); // VAT can be negative in some cases } return t.getSrcPriceCts(); diff --git a/src/main/java/alfio/model/Audit.java b/src/main/java/alfio/model/Audit.java index be0b20135c..bcdf4b3c85 100644 --- a/src/main/java/alfio/model/Audit.java +++ b/src/main/java/alfio/model/Audit.java @@ -63,6 +63,7 @@ public enum EventType { VAT_VALIDATION_SUCCESSFUL, VAT_FORMAL_VALIDATION_SUCCESSFUL, VAT_VALIDATION_SKIPPED, + VAT_CUSTOM_CONFIGURATION_APPLIED, GROUP_MEMBER_ACQUIRED, CREDIT_NOTE_ISSUED, BILLING_DATA_UPDATED, diff --git a/src/main/java/alfio/model/OrderSummary.java b/src/main/java/alfio/model/OrderSummary.java index b2536c8a9f..12d58dafcf 100644 --- a/src/main/java/alfio/model/OrderSummary.java +++ b/src/main/java/alfio/model/OrderSummary.java @@ -98,7 +98,8 @@ public int getPriceInCents() { } public String getDescriptionForPayment() { - return summary.stream().filter(r -> !r.isDiscount()).map(SummaryRow::getDescriptionForPayment).collect(Collectors.joining(", ")); + return summary.stream().filter(r -> !r.isDiscount() && !r.getTaxDetail()) + .map(SummaryRow::getDescriptionForPayment).collect(Collectors.joining(", ")); } public boolean getDisplaySplitPaymentNote() { diff --git a/src/main/java/alfio/model/PriceContainer.java b/src/main/java/alfio/model/PriceContainer.java index 63fe64b388..2320017ad3 100644 --- a/src/main/java/alfio/model/PriceContainer.java +++ b/src/main/java/alfio/model/PriceContainer.java @@ -39,6 +39,9 @@ enum VatStatus { NOT_INCLUDED(notIncludedVatCalculator, UnaryOperator.identity()), INCLUDED_EXEMPT(includedVatExtractor, BigDecimal::negate), NOT_INCLUDED_EXEMPT((price, vatPercentage) -> BigDecimal.ZERO, UnaryOperator.identity()), + // tax exemption was granted by custom rules (extension CUSTOM_TAX_POLICY_APPLICATION) + CUSTOM_INCLUDED_EXEMPT(includedVatExtractor, BigDecimal::negate), + CUSTOM_NOT_INCLUDED_EXEMPT((price, vatPercentage) -> BigDecimal.ZERO, UnaryOperator.identity()), // The following two are dedicated for handling italian-specific cases, "split payment" // VAT has to be shown on the invoice, but not charged INCLUDED_NOT_CHARGED(includedVatExtractor, UnaryOperator.identity()), @@ -62,11 +65,12 @@ public BigDecimal extractRawVAT(BigDecimal price, BigDecimal vatPercentage) { } public static boolean isVatExempt(VatStatus vatStatus) { - return vatStatus == INCLUDED_EXEMPT || vatStatus == NOT_INCLUDED_EXEMPT; + return vatStatus == INCLUDED_EXEMPT || vatStatus == NOT_INCLUDED_EXEMPT + || vatStatus == CUSTOM_INCLUDED_EXEMPT || vatStatus == CUSTOM_NOT_INCLUDED_EXEMPT; } public static boolean isVatIncluded(VatStatus vatStatus) { - return vatStatus == INCLUDED || vatStatus == INCLUDED_EXEMPT; + return vatStatus == INCLUDED || vatStatus == INCLUDED_EXEMPT || vatStatus == CUSTOM_INCLUDED_EXEMPT; } } @@ -172,9 +176,9 @@ default BigDecimal getAppliedDiscount() { default BigDecimal getNetPrice() { var vatStatus = getVatStatus(); var currencyCode = getCurrencyCode(); - if(vatStatus == VatStatus.NOT_INCLUDED_EXEMPT) { + if(vatStatus == VatStatus.NOT_INCLUDED_EXEMPT || vatStatus == VatStatus.CUSTOM_NOT_INCLUDED_EXEMPT) { return MonetaryUtil.centsToUnit(getSrcPriceCts(), currencyCode); - } else if(vatStatus == VatStatus.INCLUDED_EXEMPT) { + } else if(vatStatus == VatStatus.INCLUDED_EXEMPT || vatStatus == VatStatus.CUSTOM_INCLUDED_EXEMPT) { var rawVat = vatStatus.extractRawVAT(centsToUnit(getSrcPriceCts(), getCurrencyCode()), getVatPercentageOrZero()); return MonetaryUtil.centsToUnit(getSrcPriceCts(), currencyCode).add(rawVat); } else if(vatStatus == VatStatus.INCLUDED || vatStatus == VatStatus.INCLUDED_NOT_CHARGED) { diff --git a/src/main/java/alfio/model/SummaryRow.java b/src/main/java/alfio/model/SummaryRow.java index 43064d3848..49ff0f5690 100644 --- a/src/main/java/alfio/model/SummaryRow.java +++ b/src/main/java/alfio/model/SummaryRow.java @@ -24,7 +24,8 @@ public record SummaryRow(String name, String subTotalBeforeVat, int originalSubTotal, SummaryType type, - String taxPercentage) { + String taxPercentage, + PriceContainer.VatStatus vatStatus) { public enum SummaryType { TICKET, SUBSCRIPTION, PROMOTION_CODE, DYNAMIC_DISCOUNT, ADDITIONAL_SERVICE, APPLIED_SUBSCRIPTION, TAX_DETAIL } diff --git a/src/main/java/alfio/model/Ticket.java b/src/main/java/alfio/model/Ticket.java index e02d9576da..ce4db455dd 100644 --- a/src/main/java/alfio/model/Ticket.java +++ b/src/main/java/alfio/model/Ticket.java @@ -158,4 +158,31 @@ public String getFormattedFinalPrice() { public String getFormattedNetPrice() { return MonetaryUtil.formatCents(finalPriceCts - vatCts, currencyCode); } + + public Ticket withVatStatus(PriceContainer.VatStatus newVatStatus) { + return new Ticket( + id, + uuid, + creation, + categoryId, + status.name(), + eventId, + ticketsReservationId, + fullName, + firstName, + lastName, + email, + lockedAssignment, + userLanguage, + srcPriceCts, + finalPriceCts, + vatCts, + discountCts, + extReference, + currencyCode, + tags, + subscriptionId, + newVatStatus + ); + } } diff --git a/src/main/java/alfio/model/TicketInfo.java b/src/main/java/alfio/model/TicketInfo.java index 29ee8f536a..0209b5c51f 100644 --- a/src/main/java/alfio/model/TicketInfo.java +++ b/src/main/java/alfio/model/TicketInfo.java @@ -23,15 +23,21 @@ public class TicketInfo { private final int ticketId; + private final String ticketUuid; private final int ticketCategoryId; private final boolean ticketCategoryBounded; + private final PriceContainer.VatStatus taxPolicy; public TicketInfo(@Column("t_id") int id, + @Column("t_uuid") String ticketUuid, @Column("tc_id") int tcId, - @Column("tc_bounded") boolean bounded) { + @Column("tc_bounded") boolean bounded, + @Column("t_vat_status") PriceContainer.VatStatus taxPolicy) { this.ticketId = id; + this.ticketUuid = ticketUuid; this.ticketCategoryId = tcId; this.ticketCategoryBounded = bounded; + this.taxPolicy = taxPolicy; } } diff --git a/src/main/java/alfio/model/decorator/TicketPriceContainer.java b/src/main/java/alfio/model/decorator/TicketPriceContainer.java index aef70f57bf..3d76ebce6e 100644 --- a/src/main/java/alfio/model/decorator/TicketPriceContainer.java +++ b/src/main/java/alfio/model/decorator/TicketPriceContainer.java @@ -73,7 +73,9 @@ public static TicketPriceContainer from(Ticket t, VatStatus reservationVatStatus @Override public BigDecimal getTaxablePrice() { - if(vatStatus != VatStatus.INCLUDED_EXEMPT && vatStatus != VatStatus.NOT_INCLUDED_EXEMPT) { + if(vatStatus != VatStatus.INCLUDED_EXEMPT + && vatStatus != VatStatus.NOT_INCLUDED_EXEMPT + && vatStatus != VatStatus.CUSTOM_NOT_INCLUDED_EXEMPT) { return SummaryPriceContainer.super.getTaxablePrice(); } return BigDecimal.ZERO; diff --git a/src/main/java/alfio/model/extension/CustomTaxPolicy.java b/src/main/java/alfio/model/extension/CustomTaxPolicy.java new file mode 100644 index 0000000000..955baec5fc --- /dev/null +++ b/src/main/java/alfio/model/extension/CustomTaxPolicy.java @@ -0,0 +1,78 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.extension; + +import alfio.model.PriceContainer; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class CustomTaxPolicy { + + private final Set ticketPolicies; + + @JsonCreator + public CustomTaxPolicy(@JsonProperty("ticketPolicies") List ticketPolicies) { + this.ticketPolicies = new HashSet<>(ticketPolicies); + } + + public Set getTicketPolicies() { + return ticketPolicies; + } + + public static class TicketTaxPolicy implements Comparable { + private final String uuid; + private final PriceContainer.VatStatus taxPolicy; + + @JsonCreator + public TicketTaxPolicy(@JsonProperty("uuid") String uuid, + @JsonProperty("taxPolicy") PriceContainer.VatStatus taxPolicy) { + this.uuid = Objects.requireNonNull(uuid); + this.taxPolicy = taxPolicy; + } + + public PriceContainer.VatStatus getTaxPolicy() { + return taxPolicy; + } + + public String getUuid() { + return uuid; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TicketTaxPolicy)) return false; + TicketTaxPolicy that = (TicketTaxPolicy) o; + return Objects.equals(this.uuid, that.uuid); + } + + @Override + public int hashCode() { + return Objects.hash(uuid); + } + + @Override + public int compareTo(TicketTaxPolicy o) { + return this.equals(o) ? 0 : this.uuid.compareTo(o.uuid); + } + } +} diff --git a/src/main/java/alfio/repository/TicketRepository.java b/src/main/java/alfio/repository/TicketRepository.java index 92204bb542..aec894377d 100644 --- a/src/main/java/alfio/repository/TicketRepository.java +++ b/src/main/java/alfio/repository/TicketRepository.java @@ -51,6 +51,8 @@ public interface TicketRepository { String RESET_TICKET = " TICKETS_RESERVATION_ID = null, FULL_NAME = null, EMAIL_ADDRESS = null, SPECIAL_PRICE_ID_FK = null, LOCKED_ASSIGNMENT = false, USER_LANGUAGE = null, REMINDER_SENT = false, SRC_PRICE_CTS = 0, FINAL_PRICE_CTS = 0, VAT_CTS = 0, DISCOUNT_CTS = 0, FIRST_NAME = null, LAST_NAME = null, EXT_REFERENCE = null, TAGS = array[]::text[], VAT_STATUS = null, METADATA = '{}'::jsonb "; String RELEASE_TICKET_QUERY = "update ticket set status = 'RELEASED', uuid = :newUuid, " + RESET_TICKET + " where id = :ticketId and status in('ACQUIRED', 'PENDING', 'TO_BE_PAID') and tickets_reservation_id = :reservationId and event_id = :eventId"; + String FIND_BASIC_TICKET_INFO_BY_EVENT_ID = "select t.id t_id, t.uuid t_uuid, tc.id tc_id, tc.bounded tc_bounded, t.vat_status t_vat_status from ticket t inner join ticket_category tc on t.category_id = tc.id where t.event_id = :eventId"; + String UPDATE_TICKET_PRICE = "update ticket set src_price_cts = :srcPriceCts, final_price_cts = :finalPriceCts, vat_cts = :vatCts, discount_cts = :discountCts, currency_code = :currencyCode, vat_status = :vatStatus::VAT_STATUS where event_id = :eventId and category_id = :categoryId"; //TODO: refactor, try to move the MapSqlParameterSource inside the default method! @@ -203,11 +205,13 @@ int updateTicketPrice(@Bind("ids") List ids, @Bind("currencyCode") String currencyCode, @Bind("vatStatus") @EnumTypeAsString PriceContainer.VatStatus vatStatus); - @Query(type = QueryType.TEMPLATE, value = "update ticket set src_price_cts = :srcPriceCts, final_price_cts = :finalPriceCts," + - " vat_cts = :vatCts, discount_cts = :discountCts, currency_code = :currencyCode," + - " vat_status = :vatStatus::VAT_STATUS where event_id = :eventId and category_id = :categoryId and tickets_reservation_id = :reservationId") + @Query(type = QueryType.TEMPLATE, value = UPDATE_TICKET_PRICE + + " and tickets_reservation_id = :reservationId") String updateTicketPriceForCategoryInReservation(); + @Query(type = QueryType.TEMPLATE, value = UPDATE_TICKET_PRICE + " and uuid = :uuid") + String bulkUpdateTicketPrice(); + @Query("update ticket set tags = :tags::text[] where id in(:ids)") int updateTicketTags(@Bind("ids") List ticketIds, @Bind("tags") @Array List tags); @@ -378,14 +382,12 @@ default void resetTickets(List ticketIds) { @Query("select count(*) from ticket where status = 'RELEASED' and event_id = :eventId") Integer countWaiting(@Bind("eventId") int eventId); - @Query("select " + - " t.id t_id, " + - " tc.id tc_id, tc.bounded tc_bounded " + - " from ticket t " + - " inner join ticket_category tc on t.category_id = tc.id "+ - " where t.event_id = :eventId and t.status = 'RELEASED' and tc.expiration <= :currentTs") + @Query(FIND_BASIC_TICKET_INFO_BY_EVENT_ID + " and t.status = 'RELEASED' and tc.expiration <= :currentTs") List findReleasedBelongingToExpiredCategories(@Bind("eventId") int eventId, @Bind("currentTs") ZonedDateTime now); + @Query(FIND_BASIC_TICKET_INFO_BY_EVENT_ID + " and t.tickets_reservation_id = :reservationId") + List findBasicTicketInfoForReservation(@Bind("eventId") int eventId, @Bind("reservationId") String reservationId); + @Query(REVERT_TO_FREE) int revertToFree(@Bind("eventId") int eventId); diff --git a/src/main/java/alfio/util/TemplateResource.java b/src/main/java/alfio/util/TemplateResource.java index 733efaa21b..4c634ac4bd 100644 --- a/src/main/java/alfio/util/TemplateResource.java +++ b/src/main/java/alfio/util/TemplateResource.java @@ -366,7 +366,7 @@ private static Map prepareSampleDataForConfirmationEmail(Organiz Optional vat = Optional.of("VAT-NR"); List tickets = Collections.singletonList(new TicketWithCategory(sampleTicket(event.getZoneId()), sampleCategory(event.getZoneId()))); OrderSummary orderSummary = new OrderSummary(new TotalPrice(1000, 80, 0, 0, "CHF"), - List.of(new SummaryRow("Ticket", "10.00", "9.20", 1, "9.20", "9.20", 1000, SummaryRow.SummaryType.TICKET, null)), false, "10.00", "0.80", false, false, false, "8", PriceContainer.VatStatus.INCLUDED, "1.00"); + List.of(new SummaryRow("Ticket", "10.00", "9.20", 1, "9.20", "9.20", 1000, SummaryRow.SummaryType.TICKET, null, PriceContainer.VatStatus.INCLUDED)), false, "10.00", "0.80", false, false, false, "8", PriceContainer.VatStatus.INCLUDED, "1.00"); String baseUrl = "http://your-domain.tld"; String reservationUrl = baseUrl + "/reservation-url/"; String reservationShortId = "597e7e7b"; diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql new file mode 100644 index 0000000000..7ee84de81d --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql @@ -0,0 +1,19 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +alter type VAT_STATUS ADD VALUE 'CUSTOM_NOT_INCLUDED_EXEMPT'; +alter type VAT_STATUS ADD VALUE 'CUSTOM_INCLUDED_EXEMPT'; \ No newline at end of file diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java index fadf4a5de1..ae101a4ddd 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java @@ -83,6 +83,7 @@ import javax.imageio.ImageIO; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.math.BigDecimal; @@ -279,12 +280,7 @@ private void ensureConfiguration(ReservationFlowContext context) { protected void testBasicFlow(Supplier contextSupplier) throws Exception { // as soon as the test starts, insert the extension in the database (prepare the environment) - try (var extensionInputStream = requireNonNull(getClass().getResourceAsStream("/extension.js"))) { - List extensionStream = IOUtils.readLines(new InputStreamReader(extensionInputStream, StandardCharsets.UTF_8)); - String concatenation = String.join("\n", extensionStream).replace("EVENTS", Arrays.stream(ExtensionEvent.values()).map(ee -> "'"+ee.name()+"'").collect(Collectors.joining(","))); - extensionService.createOrUpdate(null, null, new Extension("-", "syncName", concatenation.replace("placeHolder", "false"), true)); - extensionService.createOrUpdate(null, null, new Extension("-", "asyncName", concatenation.replace("placeHolder", "true"), true)); - } + insertExtension(extensionService, "/extension.js"); List body = eventApiV2Controller.listEvents(SearchOptions.empty()).getBody(); assertNotNull(body); assertTrue(body.isEmpty()); @@ -1265,6 +1261,23 @@ protected void testBasicFlow(Supplier contextSupplier) t } + static void insertExtension(ExtensionService extensionService, String path) throws IOException { + insertExtension(extensionService, path, true, true); + } + + static void insertExtension(ExtensionService extensionService, String path, boolean async, boolean sync) throws IOException { + try (var extensionInputStream = requireNonNull(BaseReservationFlowTest.class.getResourceAsStream(path))) { + List extensionStream = IOUtils.readLines(new InputStreamReader(extensionInputStream, StandardCharsets.UTF_8)); + String concatenation = String.join("\n", extensionStream).replace("EVENTS", Arrays.stream(ExtensionEvent.values()).map(ee -> "'"+ee.name()+"'").collect(Collectors.joining(","))); + if (sync) { + extensionService.createOrUpdate(null, null, new Extension("-", "syncName", concatenation.replace("placeHolder", "false"), true)); + } + if (async) { + extensionService.createOrUpdate(null, null, new Extension("-", "asyncName", concatenation.replace("placeHolder", "true"), true)); + } + } + } + protected void validateCheckInData(ReservationFlowContext context) { } diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java new file mode 100644 index 0000000000..a22d0b39cb --- /dev/null +++ b/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java @@ -0,0 +1,253 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.v2.user.reservation; + +import alfio.TestConfiguration; +import alfio.config.DataSourceConfiguration; +import alfio.config.Initializer; +import alfio.controller.IndexController; +import alfio.controller.api.ControllerConfiguration; +import alfio.controller.api.admin.AdditionalServiceApiController; +import alfio.controller.api.admin.CheckInApiController; +import alfio.controller.api.admin.EventApiController; +import alfio.controller.api.admin.UsersApiController; +import alfio.controller.api.v1.AttendeeApiController; +import alfio.controller.api.v2.InfoApiController; +import alfio.controller.api.v2.TranslationsApiController; +import alfio.controller.api.v2.user.EventApiV2Controller; +import alfio.controller.api.v2.user.ReservationApiV2Controller; +import alfio.controller.api.v2.user.TicketApiV2Controller; +import alfio.controller.form.ContactAndTicketsForm; +import alfio.controller.form.UpdateTicketOwnerForm; +import alfio.extension.ExtensionService; +import alfio.manager.*; +import alfio.manager.user.UserManager; +import alfio.model.Event; +import alfio.model.PriceContainer; +import alfio.model.TicketCategory; +import alfio.model.metadata.AlfioMetadata; +import alfio.model.modification.DateTimeModification; +import alfio.model.modification.TicketCategoryModification; +import alfio.model.modification.TicketReservationModification; +import alfio.model.modification.TicketReservationWithOptionalCodeModification; +import alfio.repository.*; +import alfio.repository.audit.ScanAuditRepository; +import alfio.repository.system.ConfigurationRepository; +import alfio.repository.user.OrganizationRepository; +import alfio.repository.user.UserRepository; +import alfio.test.util.IntegrationTestUtil; +import alfio.util.ClockProvider; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.BeanPropertyBindingResult; +import org.testcontainers.shaded.org.apache.commons.lang.time.DateUtils; + +import java.io.IOException; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.*; + +import static alfio.controller.api.v2.user.reservation.BaseReservationFlowTest.URL_CODE_HIDDEN; +import static alfio.controller.api.v2.user.reservation.BaseReservationFlowTest.insertExtension; +import static alfio.test.util.IntegrationTestUtil.*; +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +@ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class, ControllerConfiguration.class}) +@ActiveProfiles({Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS, Initializer.PROFILE_INTEGRATION_TEST}) +@Transactional +class CustomTaxPolicyIntegrationTest { + + private final OrganizationRepository organizationRepository; + private final UserManager userManager; + private final ExtensionService extensionService; + private final ClockProvider clockProvider; + private final EventManager eventManager; + private final EventRepository eventRepository; + private final ConfigurationRepository configurationRepository; + private final TicketReservationManager ticketReservationManager; + private final TicketCategoryRepository ticketCategoryRepository; + private final ReservationApiV2Controller reservationApiV2Controller; + private final TicketRepository ticketRepository; + + @Autowired + public CustomTaxPolicyIntegrationTest(OrganizationRepository organizationRepository, + EventManager eventManager, + EventRepository eventRepository, + UserManager userManager, + ClockProvider clockProvider, + ConfigurationRepository configurationRepository, + EventStatisticsManager eventStatisticsManager, + TicketCategoryRepository ticketCategoryRepository, + TicketReservationRepository ticketReservationRepository, + EventApiController eventApiController, + TicketRepository ticketRepository, + TicketFieldRepository ticketFieldRepository, + AdditionalServiceApiController additionalServiceApiController, + SpecialPriceTokenGenerator specialPriceTokenGenerator, + SpecialPriceRepository specialPriceRepository, + CheckInApiController checkInApiController, + AttendeeApiController attendeeApiController, + UsersApiController usersApiController, + ScanAuditRepository scanAuditRepository, + AuditingRepository auditingRepository, + AdminReservationManager adminReservationManager, + TicketReservationManager ticketReservationManager, + InfoApiController infoApiController, + TranslationsApiController translationsApiController, + EventApiV2Controller eventApiV2Controller, + ReservationApiV2Controller reservationApiV2Controller, + TicketApiV2Controller ticketApiV2Controller, + IndexController indexController, + NamedParameterJdbcTemplate jdbcTemplate, + ExtensionLogRepository extensionLogRepository, + ExtensionService extensionService, + PollRepository pollRepository, + NotificationManager notificationManager, + UserRepository userRepository, + OrganizationDeleter organizationDeleter, + PromoCodeDiscountRepository promoCodeDiscountRepository, + PromoCodeRequestManager promoCodeRequestManager, + CheckInManager checkInManager) { + this.organizationRepository = organizationRepository; + this.userManager = userManager; + this.extensionService = extensionService; + this.clockProvider = clockProvider; + this.eventManager = eventManager; + this.eventRepository = eventRepository; + this.configurationRepository = configurationRepository; + this.ticketReservationManager = ticketReservationManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.reservationApiV2Controller = reservationApiV2Controller; + this.ticketRepository = ticketRepository; + } + + private ReservationFlowContext createContext(PriceContainer.VatStatus vatStatus) { + try { + IntegrationTestUtil.ensureMinimalConfiguration(configurationRepository); + insertExtension(extensionService, "/custom-tax-policy-extension.js", false, true); + List categories = Arrays.asList( + new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, AVAILABLE_SEATS, + new DateTimeModification(LocalDate.now(clockProvider.getClock()).minusDays(1), LocalTime.now(clockProvider.getClock())), + new DateTimeModification(LocalDate.now(clockProvider.getClock()).plusDays(1), LocalTime.now(clockProvider.getClock())), + DESCRIPTION, new BigDecimal("100.00"), false, "", false, null, null, null, null, null, 0, null, null, AlfioMetadata.empty()), + new TicketCategoryModification(null, "hidden", TicketCategory.TicketAccessType.INHERIT, 2, + new DateTimeModification(LocalDate.now(clockProvider.getClock()).minusDays(1), LocalTime.now(clockProvider.getClock())), + new DateTimeModification(LocalDate.now(clockProvider.getClock()).plusDays(1), LocalTime.now(clockProvider.getClock())), + DESCRIPTION, new BigDecimal("10.00"), true, "", true, URL_CODE_HIDDEN, null, null, null, null, 0, null, null, AlfioMetadata.empty()) + ); + Pair eventAndUser = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository, List.of(), Event.EventFormat.IN_PERSON, vatStatus); + return new ReservationFlowContext(eventAndUser.getLeft(), eventAndUser.getRight() + "_owner"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + void triggerCustomTaxPolicyTaxIncluded() { + var context = createContext(PriceContainer.VatStatus.INCLUDED); + var categories = ticketCategoryRepository.findAllTicketCategories(context.event.getId()); + assertEquals(2, categories.size()); + var ticketRequest = new TicketReservationModification(); + ticketRequest.setQuantity(2); + ticketRequest.setTicketCategoryId(categories.get(0).getId()); + + var request = List.of(new TicketReservationWithOptionalCodeModification(ticketRequest, Optional.empty())); + var reservationId = ticketReservationManager.createTicketReservation(context.event, request, List.of(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); + + var totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); + assertEquals(20000, totalPrice.getPriceWithVAT()); + + var tickets = ticketRepository.findTicketsInReservation(reservationId); + assertEquals(2, tickets.size()); + var firstUuid = tickets.get(0).getUuid(); + var secondUuid = tickets.get(1).getUuid(); + var contactAndTicketsForm = new ContactAndTicketsForm(); + contactAndTicketsForm.setFirstName("The"); + contactAndTicketsForm.setLastName("Customer"); + contactAndTicketsForm.setEmail("email@customer.com"); + contactAndTicketsForm.setTickets(Map.of( + firstUuid, updateTicketOwnerForm("example@example.org"), + secondUuid, updateTicketOwnerForm("example@example1.org") + )); + var bindingResult = new BeanPropertyBindingResult(contactAndTicketsForm, "form"); + var response = reservationApiV2Controller.validateToOverview(reservationId, "en", false, contactAndTicketsForm, bindingResult, null); + assertTrue(response.getStatusCode().is2xxSuccessful()); + assertNotNull(response.getBody()); + assertTrue(response.getBody().isSuccess()); + // verify that first ticket has the expected tax settings + assertEquals(PriceContainer.VatStatus.CUSTOM_INCLUDED_EXEMPT, ticketRepository.findByUUID(firstUuid).getVatStatus()); + assertEquals(PriceContainer.VatStatus.INCLUDED, ticketRepository.findByUUID(secondUuid).getVatStatus()); + totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); + assertEquals(19901, totalPrice.getPriceWithVAT()); + } + + @Test + void triggerCustomTaxPolicyTaxNotIncluded() { + var context = createContext(PriceContainer.VatStatus.NOT_INCLUDED); + var categories = ticketCategoryRepository.findAllTicketCategories(context.event.getId()); + assertEquals(2, categories.size()); + var ticketRequest = new TicketReservationModification(); + ticketRequest.setQuantity(2); + ticketRequest.setTicketCategoryId(categories.get(0).getId()); + + var request = List.of(new TicketReservationWithOptionalCodeModification(ticketRequest, Optional.empty())); + var reservationId = ticketReservationManager.createTicketReservation(context.event, request, List.of(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); + + var totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); + assertEquals(20200, totalPrice.getPriceWithVAT()); + + var tickets = ticketRepository.findTicketsInReservation(reservationId); + assertEquals(2, tickets.size()); + var firstUuid = tickets.get(0).getUuid(); + var secondUuid = tickets.get(1).getUuid(); + var contactAndTicketsForm = new ContactAndTicketsForm(); + contactAndTicketsForm.setFirstName("The"); + contactAndTicketsForm.setLastName("Customer"); + contactAndTicketsForm.setEmail("email@customer.com"); + contactAndTicketsForm.setTickets(Map.of( + firstUuid, updateTicketOwnerForm("example@example.org"), + secondUuid, updateTicketOwnerForm("example@example1.org") + )); + var bindingResult = new BeanPropertyBindingResult(contactAndTicketsForm, "form"); + var response = reservationApiV2Controller.validateToOverview(reservationId, "en", false, contactAndTicketsForm, bindingResult, null); + assertTrue(response.getStatusCode().is2xxSuccessful()); + assertNotNull(response.getBody()); + assertTrue(response.getBody().isSuccess()); + // verify that first ticket has the expected tax settings + assertEquals(PriceContainer.VatStatus.CUSTOM_NOT_INCLUDED_EXEMPT, ticketRepository.findByUUID(firstUuid).getVatStatus()); + assertEquals(PriceContainer.VatStatus.NOT_INCLUDED, ticketRepository.findByUUID(secondUuid).getVatStatus()); + totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); + assertEquals(20100, totalPrice.getPriceWithVAT()); + } + + private static UpdateTicketOwnerForm updateTicketOwnerForm(String email) { + var form = new UpdateTicketOwnerForm(); + form.setFirstName("first"); + form.setLastName("last"); + form.setEmail(email); + form.setUserLanguage("en"); + return form; + } +} diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java index 77e4cc683d..81e5d2736c 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java @@ -77,6 +77,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import static alfio.manager.support.extension.ExtensionEvent.*; import static alfio.test.util.IntegrationTestUtil.*; @@ -289,7 +290,7 @@ private void processWebHook(String filename, String reservationId) { var response = stripePaymentWebhookController.receivePaymentConfirmation(signedHeader, httpRequest); assertNotNull(response); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(APPLICATION_JSON_UTF8, response.getHeaders().getContentType().toString()); + assertEquals(APPLICATION_JSON_UTF8, Objects.requireNonNull(response.getHeaders().getContentType()).toString()); } catch (Exception ex) { throw new IllegalStateException(ex); } diff --git a/src/test/java/alfio/manager/ExtensionManagerTest.java b/src/test/java/alfio/manager/ExtensionManagerTest.java index 02fb2716b2..03d40bb093 100644 --- a/src/test/java/alfio/manager/ExtensionManagerTest.java +++ b/src/test/java/alfio/manager/ExtensionManagerTest.java @@ -50,7 +50,7 @@ void setUp() { when(eventRepository.findOrganizationIdByEventId(1)).thenReturn(1); when(eventRepository.findById(1)).thenReturn(event); extensionService = mock(ExtensionService.class); - extensionManager = new ExtensionManager(extensionService, eventRepository, null, null, mock(ConfigurationManager.class), null); + extensionManager = new ExtensionManager(extensionService, eventRepository, null, null, mock(ConfigurationManager.class), null, null); } @Test diff --git a/src/test/java/alfio/test/util/IntegrationTestUtil.java b/src/test/java/alfio/test/util/IntegrationTestUtil.java index 6cc799c695..3dd79133d6 100644 --- a/src/test/java/alfio/test/util/IntegrationTestUtil.java +++ b/src/test/java/alfio/test/util/IntegrationTestUtil.java @@ -102,6 +102,17 @@ public static Pair initEvent(List cat List additionalServices, Event.EventFormat eventFormat) { + return initEvent(categories, organizationRepository, userManager, eventManager, eventRepository, additionalServices, eventFormat, PriceContainer.VatStatus.INCLUDED); + } + + public static Pair initEvent(List categories, + OrganizationRepository organizationRepository, + UserManager userManager, + EventManager eventManager, + EventRepository eventRepository, + List additionalServices, + Event.EventFormat eventFormat, + PriceContainer.VatStatus eventVatStatus) { String organizationName = UUID.randomUUID().toString(); String username = UUID.randomUUID().toString(); String eventName = UUID.randomUUID().toString(); @@ -120,11 +131,11 @@ public static Pair initEvent(List cat desc.put("de", "muh description"); EventModification em = new EventModification(null, eventFormat, "url", "url", "url", "privacy","url", null, - eventName, "event display name", organization.getId(), - "muh location", "0.0", "0.0", ClockProvider.clock().getZone().getId(), desc, - new DateTimeModification(LocalDate.now(ClockProvider.clock()).plusDays(5), LocalTime.now(ClockProvider.clock())), - new DateTimeModification(expiration.toLocalDate(), expiration.toLocalTime()), - BigDecimal.TEN, "CHF", AVAILABLE_SEATS, BigDecimal.ONE, true, Collections.singletonList(PaymentProxy.OFFLINE), categories, false, new LocationDescriptor("","","",""), 7, null, additionalServices, AlfioMetadata.empty(), List.of()); + eventName, "event display name", organization.getId(), + "muh location", "0.0", "0.0", ClockProvider.clock().getZone().getId(), desc, + new DateTimeModification(LocalDate.now(ClockProvider.clock()).plusDays(5), LocalTime.now(ClockProvider.clock())), + new DateTimeModification(expiration.toLocalDate(), expiration.toLocalTime()), + BigDecimal.TEN, "CHF", AVAILABLE_SEATS, BigDecimal.ONE, PriceContainer.VatStatus.isVatIncluded(eventVatStatus), Collections.singletonList(PaymentProxy.OFFLINE), categories, false, new LocationDescriptor("","","",""), 7, null, additionalServices, AlfioMetadata.empty(), List.of()); eventManager.createEvent(em, username); Event event = eventManager.getSingleEvent(eventName, username); Assertions.assertEquals(AVAILABLE_SEATS, eventRepository.countExistingTickets(event.getId()).intValue()); diff --git a/src/test/resources/custom-tax-policy-extension.js b/src/test/resources/custom-tax-policy-extension.js new file mode 100644 index 0000000000..04118780e0 --- /dev/null +++ b/src/test/resources/custom-tax-policy-extension.js @@ -0,0 +1,56 @@ +/** + * The script metadata object describes whether your extension should be invoked asynchronously, and which events it supports + * @returns {{ async: boolean, events: string[] }} + */ +function getScriptMetadata() { + return { + id: 'customTaxPolicyApplicationExample', // optional: id and version will be used later as a mechanism for checking if the script has a newer version + displayName: 'Custom Tax Policy Application Example', //mandatory: the name displayed in the configuration page + version: 0, // optional + async: false, + events: [ + 'CUSTOM_TAX_POLICY_APPLICATION' + ] + }; +} +/** + * Executes the extension. + * @param scriptEvent + * @returns Object + */ +function executeScript(scriptEvent) { + console.log('entering customTaxPolicyApplicationExample for reservation', reservationId); + // in this simple example we need to remove taxes if the attendee email ends with "@example.org" + var keys = Object.keys(reservationForm.tickets); + var containsModifiedElements = false; + var out = []; + for (i = 0; i < keys.length; i++) { + var uuid = keys[i]; + var attendee = reservationForm.tickets[uuid]; + var ticketInfo = ticketInfoByUuid[uuid]; + var category = categoriesById[ticketInfo.ticketCategoryId]; + var originalTaxPolicy = ticketInfo.taxPolicy; + if (!category.free && attendee.email.endsWith('@example.org')) { + console.log('found attendee with matching email!'); + out.push({ + uuid: uuid, + taxPolicy: originalTaxPolicy == 'INCLUDED' ? 'CUSTOM_INCLUDED_EXEMPT' : 'CUSTOM_NOT_INCLUDED_EXEMPT' + }); + containsModifiedElements = true; + } else { + out.push({ + uuid: uuid, + taxPolicy: originalTaxPolicy + }); + } + } + + if (!containsModifiedElements) { + // since nothing was modified, we return "null" to continue with the original validation process + return null; + } + + return { + ticketPolicies: out + }; +} From f09bfe8300a171afb1f71ce71aa4f1920e5957b7 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sun, 12 Feb 2023 16:31:53 +0100 Subject: [PATCH 151/218] fix errors after cherry-pick --- .../java/alfio/manager/ExtensionManager.java | 4 +- .../CustomTaxPolicyIntegrationTest.java | 10 +- src/test/resources/api/descriptor.json | 294 +++++++++--------- 3 files changed, 157 insertions(+), 151 deletions(-) diff --git a/src/main/java/alfio/manager/ExtensionManager.java b/src/main/java/alfio/manager/ExtensionManager.java index f0269234d7..f81d7e5818 100644 --- a/src/main/java/alfio/manager/ExtensionManager.java +++ b/src/main/java/alfio/manager/ExtensionManager.java @@ -93,13 +93,15 @@ public ExtensionManager(ExtensionService extensionService, TicketReservationRepository ticketReservationRepository, TicketRepository ticketRepository, ConfigurationManager configurationManager, - TransactionRepository transactionRepository) { + TransactionRepository transactionRepository, + TicketCategoryRepository ticketCategoryRepository) { this.extensionService = extensionService; this.eventRepository = eventRepository; this.ticketReservationRepository = ticketReservationRepository; this.ticketRepository = ticketRepository; this.configurationManager = configurationManager; this.transactionRepository = transactionRepository; + this.ticketCategoryRepository = ticketCategoryRepository; } diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java index a22d0b39cb..eead9b8f04 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java @@ -51,6 +51,7 @@ import alfio.repository.user.UserRepository; import alfio.test.util.IntegrationTestUtil; import alfio.util.ClockProvider; +import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -60,7 +61,6 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BeanPropertyBindingResult; -import org.testcontainers.shaded.org.apache.commons.lang.time.DateUtils; import java.io.IOException; import java.math.BigDecimal; @@ -177,7 +177,7 @@ void triggerCustomTaxPolicyTaxIncluded() { var reservationId = ticketReservationManager.createTicketReservation(context.event, request, List.of(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); var totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); - assertEquals(20000, totalPrice.getPriceWithVAT()); + assertEquals(20000, totalPrice.priceWithVAT()); var tickets = ticketRepository.findTicketsInReservation(reservationId); assertEquals(2, tickets.size()); @@ -200,7 +200,7 @@ secondUuid, updateTicketOwnerForm("example@example1.org") assertEquals(PriceContainer.VatStatus.CUSTOM_INCLUDED_EXEMPT, ticketRepository.findByUUID(firstUuid).getVatStatus()); assertEquals(PriceContainer.VatStatus.INCLUDED, ticketRepository.findByUUID(secondUuid).getVatStatus()); totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); - assertEquals(19901, totalPrice.getPriceWithVAT()); + assertEquals(19901, totalPrice.priceWithVAT()); } @Test @@ -216,7 +216,7 @@ void triggerCustomTaxPolicyTaxNotIncluded() { var reservationId = ticketReservationManager.createTicketReservation(context.event, request, List.of(), DateUtils.addDays(new Date(), 1), Optional.empty(), Locale.ENGLISH, false, null); var totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); - assertEquals(20200, totalPrice.getPriceWithVAT()); + assertEquals(20200, totalPrice.priceWithVAT()); var tickets = ticketRepository.findTicketsInReservation(reservationId); assertEquals(2, tickets.size()); @@ -239,7 +239,7 @@ secondUuid, updateTicketOwnerForm("example@example1.org") assertEquals(PriceContainer.VatStatus.CUSTOM_NOT_INCLUDED_EXEMPT, ticketRepository.findByUUID(firstUuid).getVatStatus()); assertEquals(PriceContainer.VatStatus.NOT_INCLUDED, ticketRepository.findByUUID(secondUuid).getVatStatus()); totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId).getLeft(); - assertEquals(20100, totalPrice.getPriceWithVAT()); + assertEquals(20100, totalPrice.priceWithVAT()); } private static UpdateTicketOwnerForm updateTicketOwnerForm(String email) { diff --git a/src/test/resources/api/descriptor.json b/src/test/resources/api/descriptor.json index 9b8e1ac60d..c0b32be673 100644 --- a/src/test/resources/api/descriptor.json +++ b/src/test/resources/api/descriptor.json @@ -25864,7 +25864,7 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "refundedAmount" : { "type" : "string" @@ -26093,13 +26093,13 @@ "valid" : { "type" : "boolean" }, - "pin" : { + "formattedValidityFrom" : { "type" : "string" }, - "formattedValidityTo" : { + "pin" : { "type" : "string" }, - "formattedValidityFrom" : { + "formattedValidityTo" : { "type" : "string" } } @@ -26154,14 +26154,18 @@ "taxPercentage" : { "type" : "string" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "discount" : { "type" : "boolean" }, - "descriptionForPayment" : { - "type" : "string" - }, "taxDetail" : { "type" : "boolean" + }, + "descriptionForPayment" : { + "type" : "string" } } }, @@ -26246,7 +26250,10 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, + "formattedNetPrice" : { + "type" : "string" }, "assigned" : { "type" : "boolean" @@ -26256,9 +26263,6 @@ }, "formattedFinalPrice" : { "type" : "string" - }, - "formattedNetPrice" : { - "type" : "string" } } }, @@ -26406,7 +26410,7 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "vatNr" : { "type" : "string" @@ -26456,6 +26460,15 @@ "cancelled" : { "type" : "boolean" }, + "stuck" : { + "type" : "boolean" + }, + "hasBillingAddress" : { + "type" : "boolean" + }, + "hasVatNumber" : { + "type" : "boolean" + }, "hasInvoiceNumber" : { "type" : "boolean" }, @@ -26477,15 +26490,6 @@ "hasBeenPaid" : { "type" : "boolean" }, - "stuck" : { - "type" : "boolean" - }, - "hasBillingAddress" : { - "type" : "boolean" - }, - "hasVatNumber" : { - "type" : "boolean" - }, "finalPrice" : { "type" : "number" }, @@ -26585,6 +26589,32 @@ "currencyCode" : { "type" : "string" }, + "stuck" : { + "type" : "boolean" + }, + "reminderSent" : { + "type" : "boolean" + }, + "hasBillingAddress" : { + "type" : "boolean" + }, + "hasVatNumber" : { + "type" : "boolean" + }, + "latestReminder" : { + "type" : "string", + "format" : "date-time" + }, + "invoiceModel" : { + "type" : "string" + }, + "usedVatPercent" : { + "type" : "number" + }, + "creationTimestamp" : { + "type" : "string", + "format" : "date-time" + }, "status" : { "type" : "string", "enum" : [ "PENDING", "IN_PAYMENT", "EXTERNAL_PROCESSING_PAYMENT", "WAITING_EXTERNAL_CONFIRMATION", "OFFLINE_PAYMENT", "DEFERRED_OFFLINE_PAYMENT", "COMPLETE", "STUCK", "CANCELLED", "CREDIT_NOTE_ISSUED" ] @@ -26597,18 +26627,16 @@ "type" : "string", "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "hasInvoiceNumber" : { "type" : "boolean" }, "invoiceNumber" : { "type" : "string" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, "finalPriceCts" : { "type" : "integer", "format" : "int32" @@ -26630,9 +26658,11 @@ "invoiceRequested" : { "type" : "boolean" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" }, "srcPriceCts" : { "type" : "integer", @@ -26709,32 +26739,6 @@ }, "taxablePrice" : { "type" : "number" - }, - "stuck" : { - "type" : "boolean" - }, - "reminderSent" : { - "type" : "boolean" - }, - "hasBillingAddress" : { - "type" : "boolean" - }, - "hasVatNumber" : { - "type" : "boolean" - }, - "latestReminder" : { - "type" : "string", - "format" : "date-time" - }, - "invoiceModel" : { - "type" : "string" - }, - "usedVatPercent" : { - "type" : "number" - }, - "creationTimestamp" : { - "type" : "string", - "format" : "date-time" } } }, @@ -27871,7 +27875,7 @@ "taxPolicy" : { "type" : "string", "writeOnly" : true, - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "currencyCode" : { "type" : "string", @@ -28460,6 +28464,12 @@ "currencyCode" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] @@ -28477,15 +28487,9 @@ "type" : "integer", "format" : "int32" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "subscriptionId" : { + "vatStatus" : { "type" : "string", - "format" : "uuid" + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "finalPriceCts" : { "type" : "integer", @@ -28499,9 +28503,15 @@ "type" : "integer", "format" : "int32" }, - "vatStatus" : { + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "subscriptionId" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "format" : "uuid" }, "srcPriceCts" : { "type" : "integer", @@ -28536,12 +28546,6 @@ "formattedFinalPrice" : { "type" : "string" }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "categoryName" : { "type" : "string" } @@ -28881,7 +28885,7 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "currency" : { "type" : "string" @@ -29025,12 +29029,12 @@ "type" : "string", "format" : "date-time" }, + "overlap" : { + "type" : "boolean" + }, "instant" : { "type" : "string", "format" : "date-time" - }, - "overlap" : { - "type" : "boolean" } } } @@ -29419,7 +29423,7 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "priceInCents" : { "type" : "integer", @@ -29783,6 +29787,12 @@ "currencyCode" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] @@ -29800,15 +29810,9 @@ "type" : "integer", "format" : "int32" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "subscriptionId" : { + "vatStatus" : { "type" : "string", - "format" : "uuid" + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "finalPriceCts" : { "type" : "integer", @@ -29822,9 +29826,15 @@ "type" : "integer", "format" : "int32" }, - "vatStatus" : { + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "subscriptionId" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "format" : "uuid" }, "srcPriceCts" : { "type" : "integer", @@ -29858,12 +29868,6 @@ }, "formattedFinalPrice" : { "type" : "string" - }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" } } }, @@ -30020,7 +30024,7 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "items" : { "type" : "array", @@ -30179,12 +30183,12 @@ "type" : "string", "format" : "date-time" }, + "overlap" : { + "type" : "boolean" + }, "instant" : { "type" : "string", "format" : "date-time" - }, - "overlap" : { - "type" : "boolean" } } } @@ -31657,7 +31661,7 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "currency" : { "type" : "string" @@ -31860,6 +31864,15 @@ "currencyCode" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, + "stuck" : { + "type" : "boolean" + }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] @@ -31880,15 +31893,9 @@ "type" : "integer", "format" : "int32" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "subscriptionId" : { + "vatStatus" : { "type" : "string", - "format" : "uuid" + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "finalPriceCts" : { "type" : "integer", @@ -31902,9 +31909,15 @@ "type" : "integer", "format" : "int32" }, - "vatStatus" : { + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "subscriptionId" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "format" : "uuid" }, "srcPriceCts" : { "type" : "integer", @@ -31942,15 +31955,6 @@ "formattedFinalPrice" : { "type" : "string" }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, - "stuck" : { - "type" : "boolean" - }, "transactionTimestamp" : { "type" : "string", "format" : "date-time" @@ -32108,6 +32112,12 @@ "currencyCode" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] @@ -32125,15 +32135,9 @@ "type" : "integer", "format" : "int32" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "subscriptionId" : { + "vatStatus" : { "type" : "string", - "format" : "uuid" + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "finalPriceCts" : { "type" : "integer", @@ -32147,9 +32151,15 @@ "type" : "integer", "format" : "int32" }, - "vatStatus" : { + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "subscriptionId" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "format" : "uuid" }, "srcPriceCts" : { "type" : "integer", @@ -32184,12 +32194,6 @@ "formattedFinalPrice" : { "type" : "string" }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "additionalFields" : { "type" : "object", "additionalProperties" : { @@ -32721,7 +32725,7 @@ }, "eventType" : { "type" : "string", - "enum" : [ "RESERVATION_CREATE", "RESERVATION_COMPLETE", "RESERVATION_OFFLINE_PAYMENT_CONFIRMED", "CANCEL_RESERVATION_EXPIRED", "CANCEL_RESERVATION", "RESET_PAYMENT", "INIT_PAYMENT", "UPDATE_EVENT", "CANCEL_TICKET", "PAYMENT_CONFIRMED", "PAYMENT_ALREADY_CONFIRMED", "REFUND", "REFUND_ATTEMPT_FAILED", "CHECK_IN", "MANUAL_CHECK_IN", "REVERT_CHECK_IN", "BADGE_SCAN", "UPDATE_TICKET", "TAG_TICKET", "UNTAG_TICKET", "UPDATE_TICKET_CATEGORY", "UPDATE_INVOICE", "FORCED_UPDATE_INVOICE", "TERMS_CONDITION_ACCEPTED", "PRIVACY_POLICY_ACCEPTED", "EXTERNAL_INVOICE_NUMBER", "EXTERNAL_CREDIT_NOTE_NUMBER", "VAT_VALIDATION_SUCCESSFUL", "VAT_FORMAL_VALIDATION_SUCCESSFUL", "VAT_VALIDATION_SKIPPED", "GROUP_MEMBER_ACQUIRED", "CREDIT_NOTE_ISSUED", "BILLING_DATA_UPDATED", "BILLING_DOCUMENT_GENERATED", "BILLING_DOCUMENT_INVALIDATED", "BILLING_DOCUMENT_RESTORED", "FORCE_VAT_APPLICATION", "PAYMENT_FAILED", "MATCHING_PAYMENT_FOUND", "MATCHING_PAYMENT_DISCARDED", "AUTOMATIC_PAYMENT_CONFIRMATION", "AUTOMATIC_PAYMENT_CONFIRMATION_FAILED", "DYNAMIC_DISCOUNT_CODE_CREATED", "SUBSCRIPTION_ACQUIRED", "UPDATE_TICKET_METADATA", "WARNING_IGNORED" ] + "enum" : [ "RESERVATION_CREATE", "RESERVATION_COMPLETE", "RESERVATION_OFFLINE_PAYMENT_CONFIRMED", "CANCEL_RESERVATION_EXPIRED", "CANCEL_RESERVATION", "RESET_PAYMENT", "INIT_PAYMENT", "UPDATE_EVENT", "CANCEL_TICKET", "PAYMENT_CONFIRMED", "PAYMENT_ALREADY_CONFIRMED", "REFUND", "REFUND_ATTEMPT_FAILED", "CHECK_IN", "MANUAL_CHECK_IN", "REVERT_CHECK_IN", "BADGE_SCAN", "UPDATE_TICKET", "TAG_TICKET", "UNTAG_TICKET", "UPDATE_TICKET_CATEGORY", "UPDATE_INVOICE", "FORCED_UPDATE_INVOICE", "TERMS_CONDITION_ACCEPTED", "PRIVACY_POLICY_ACCEPTED", "EXTERNAL_INVOICE_NUMBER", "EXTERNAL_CREDIT_NOTE_NUMBER", "VAT_VALIDATION_SUCCESSFUL", "VAT_FORMAL_VALIDATION_SUCCESSFUL", "VAT_VALIDATION_SKIPPED", "VAT_CUSTOM_CONFIGURATION_APPLIED", "GROUP_MEMBER_ACQUIRED", "CREDIT_NOTE_ISSUED", "BILLING_DATA_UPDATED", "BILLING_DOCUMENT_GENERATED", "BILLING_DOCUMENT_INVALIDATED", "BILLING_DOCUMENT_RESTORED", "FORCE_VAT_APPLICATION", "PAYMENT_FAILED", "MATCHING_PAYMENT_FOUND", "MATCHING_PAYMENT_DISCARDED", "AUTOMATIC_PAYMENT_CONFIRMATION", "AUTOMATIC_PAYMENT_CONFIRMATION_FAILED", "DYNAMIC_DISCOUNT_CODE_CREATED", "SUBSCRIPTION_ACQUIRED", "UPDATE_TICKET_METADATA", "WARNING_IGNORED" ] }, "eventTime" : { "type" : "string", @@ -33297,9 +33301,6 @@ "expired" : { "type" : "boolean" }, - "formattedEnd" : { - "type" : "string" - }, "notSoldTickets" : { "type" : "integer", "format" : "int32" @@ -33320,6 +33321,9 @@ "type" : "integer", "format" : "int32" }, + "formattedEnd" : { + "type" : "string" + }, "warningNeeded" : { "type" : "boolean" }, @@ -33664,12 +33668,6 @@ "editable" : { "type" : "boolean" }, - "disabledValues" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, "inputField" : { "type" : "boolean" }, @@ -33697,6 +33695,12 @@ "type" : "integer", "format" : "int32" } + }, + "disabledValues" : { + "type" : "array", + "items" : { + "type" : "string" + } } } }, @@ -33816,7 +33820,7 @@ }, "vatStatus" : { "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, "version" : { "type" : "string" From 0ea5d7b9357b69e718dd6ab0eba6146311869183 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sat, 11 Feb 2023 21:41:56 +0100 Subject: [PATCH 152/218] implement reservation export (#1194) - cherry-picked from 1e9bedf25c3c626f750c5ccf3531004acaa9ee5a --- .../api/admin/EventApiController.java | 6 + .../api/admin/ExportApiController.java | 111 +++++++++++++ src/main/java/alfio/manager/EventManager.java | 4 + .../java/alfio/manager/ExportManager.java | 48 ++++++ .../alfio/model/PromoCodeUsageResult.java | 148 +----------------- .../java/alfio/model/ReservationsByEvent.java | 58 +++++++ .../alfio/model/support/EventBasicInfo.java | 44 ++++++ .../alfio/model/support/ReservationInfo.java | 103 ++++++++++++ .../java/alfio/model/support/TicketInfo.java | 61 ++++++++ .../alfio/repository/EventRepository.java | 2 + .../alfio/repository/ExportRepository.java | 65 ++++++++ src/main/java/alfio/util/ExportUtils.java | 26 ++- ...rate__016_VIEW_promocode_usage_details.sql | 3 +- .../alfio/web-templates/admin-index.ms | 1 + .../export-reservations-button.html | 5 + .../export-reservations-form.html | 43 +++++ .../export-reservations.js | 60 +++++++ .../js/admin/ng-app/admin-application.js | 1 + .../resources/js/admin/service/service.js | 3 + .../reservation/BaseReservationFlowTest.java | 22 +++ .../CustomTaxPolicyIntegrationTest.java | 49 +----- ...countedReservationFlowIntegrationTest.java | 6 +- ...idEventReservationFlowIntegrationTest.java | 6 +- ...neEventReservationFlowIntegrationTest.java | 6 +- ...nFlowAuthenticatedUserIntegrationTest.java | 6 +- .../ReservationFlowIntegrationTest.java | 6 +- ...onFlowWithSubscriptionIntegrationTest.java | 6 +- .../StripeReservationFlowIntegrationTest.java | 6 +- 28 files changed, 701 insertions(+), 204 deletions(-) create mode 100644 src/main/java/alfio/controller/api/admin/ExportApiController.java create mode 100644 src/main/java/alfio/manager/ExportManager.java create mode 100644 src/main/java/alfio/model/ReservationsByEvent.java create mode 100644 src/main/java/alfio/model/support/EventBasicInfo.java create mode 100644 src/main/java/alfio/model/support/ReservationInfo.java create mode 100644 src/main/java/alfio/model/support/TicketInfo.java create mode 100644 src/main/java/alfio/repository/ExportRepository.java create mode 100644 src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-button.html create mode 100644 src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-form.html create mode 100644 src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations.js diff --git a/src/main/java/alfio/controller/api/admin/EventApiController.java b/src/main/java/alfio/controller/api/admin/EventApiController.java index a7df9e638a..03d405ebda 100644 --- a/src/main/java/alfio/controller/api/admin/EventApiController.java +++ b/src/main/java/alfio/controller/api/admin/EventApiController.java @@ -188,6 +188,12 @@ public List getAllEvents(Principal principal) { return eventStatisticsManager.getAllEventsWithStatistics(principal.getName()); } + @GetMapping("/events-count") + public ResponseEntity getEventsCount() { + return ResponseEntity.ok(eventManager.getEventsCount()); + } + + @GetMapping("/active-events") public List getAllActiveEvents(Principal principal) { return eventStatisticsManager.getAllEventsWithStatisticsFilteredBy(principal.getName(), event -> !event.expiredSince(14)); diff --git a/src/main/java/alfio/controller/api/admin/ExportApiController.java b/src/main/java/alfio/controller/api/admin/ExportApiController.java new file mode 100644 index 0000000000..1025d8b3a2 --- /dev/null +++ b/src/main/java/alfio/controller/api/admin/ExportApiController.java @@ -0,0 +1,111 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.admin; + +import alfio.manager.ExportManager; +import alfio.model.ReservationsByEvent; +import alfio.model.support.ReservationInfo; +import ch.digitalfondue.basicxlsx.StreamingWorkbook; +import ch.digitalfondue.basicxlsx.Style; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.LocalDate; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Stream; + +import static alfio.util.ExportUtils.addSheetToWorkbook; +import static alfio.util.ExportUtils.exportExcel; +import static java.util.Objects.requireNonNull; + +@RestController +@RequestMapping("/admin/api/export") +public class ExportApiController { + + private final ExportManager exportManager; + + public ExportApiController(ExportManager exportManager) { + this.exportManager = exportManager; + } + + @GetMapping("/reservations") + public void downloadAllEvents(@RequestParam(name = "from") String from, + @RequestParam(name = "to") String to, + HttpServletResponse response) throws IOException { + var allEvents = exportManager.reservationsForInterval(LocalDate.parse(requireNonNull(from)), LocalDate.parse(requireNonNull(to))); + if (allEvents.isEmpty()) { + response.setContentType("text/plain"); + response.setStatus(HttpStatus.PRECONDITION_REQUIRED.value()); + response.getWriter().write("No reservations found for the selected period"); + } else { + exportExcel("all-reservations.xlsx", response, workbook -> writeSheets(allEvents, workbook)); + } + } + + private static void writeSheets(List allEvents, StreamingWorkbook workbook) { + var header = new String[] { + "Event Name", + "Reservation ID", + "Date", + "Invoice #", + "Contact First Name", + "Contact Last Name", + "Payment Type", + "Amount", + "Currency", + "Ticket Type", + "Attendee First Name", + "Attendee Last Name", + "Status" + }; + var headerStyle = workbook.defineStyle().font().bold(true).build(); + allEvents.stream().sorted(Comparator.comparing(ReservationsByEvent::getEventShortName)) + .forEach(e -> addSheet(workbook, header, headerStyle, e)); + } + + private static void addSheet(StreamingWorkbook workbook, String[] header, Style headerStyle, ReservationsByEvent eventWithReservations) { + var rowData = eventWithReservations.getReservations().stream() + .sorted(Comparator.comparing(ReservationInfo::getConfirmationTimestamp)) + .flatMap(r -> ticketRows(eventWithReservations, r)); + addSheetToWorkbook(eventWithReservations.getEventShortName(), header, rowData, workbook, headerStyle); + } + + private static Stream ticketRows(ReservationsByEvent eventWithReservations, ReservationInfo r) { + return r.getTickets().stream() + .map(t -> new String[] { + eventWithReservations.getDisplayName(), + r.getId(), + r.getConfirmationTimestamp(), + r.getInvoiceNumber(), + r.getFirstName(), + r.getLastName(), + r.getPaymentType().name(), + r.getFormattedAmount(), + r.getCurrency(), + t.getType(), + t.getFirstName(), + t.getLastName(), + t.getStatus() + }); + } +} diff --git a/src/main/java/alfio/manager/EventManager.java b/src/main/java/alfio/manager/EventManager.java index d4a1bace2f..97a2b9b3b0 100644 --- a/src/main/java/alfio/manager/EventManager.java +++ b/src/main/java/alfio/manager/EventManager.java @@ -1240,5 +1240,9 @@ public List getLinkedSubscriptionIds(int eventId, int organizationId) { return subscriptionRepository.findLinkedSubscriptionIds(eventId, organizationId); } + public int getEventsCount() { + return eventRepository.countEvents(); + } + } diff --git a/src/main/java/alfio/manager/ExportManager.java b/src/main/java/alfio/manager/ExportManager.java new file mode 100644 index 0000000000..98f2e8401a --- /dev/null +++ b/src/main/java/alfio/manager/ExportManager.java @@ -0,0 +1,48 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager; + +import alfio.model.ReservationsByEvent; +import alfio.repository.ExportRepository; +import alfio.util.ClockProvider; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.List; + +@Component +public class ExportManager { + + private final ExportRepository exportRepository; + private final ClockProvider clockProvider; + + public ExportManager(ExportRepository exportRepository, + ClockProvider clockProvider) { + this.exportRepository = exportRepository; + this.clockProvider = clockProvider; + } + + public List reservationsForInterval(LocalDate from, LocalDate to) { + if (from.isAfter(to)) { + throw new IllegalArgumentException("Wrong interval"); + } + var zoneId = clockProvider.getClock().getZone(); + var zonedFrom = from.atStartOfDay().atZone(zoneId); + var zonedTo = to.plusDays(1).atStartOfDay().minusSeconds(1).atZone(zoneId); + return exportRepository.allReservationsForInterval(zonedFrom, zonedTo); + } +} diff --git a/src/main/java/alfio/model/PromoCodeUsageResult.java b/src/main/java/alfio/model/PromoCodeUsageResult.java index 1bcd272990..db052d5b01 100644 --- a/src/main/java/alfio/model/PromoCodeUsageResult.java +++ b/src/main/java/alfio/model/PromoCodeUsageResult.java @@ -16,12 +16,10 @@ */ package alfio.model; -import alfio.model.transaction.PaymentProxy; +import alfio.model.support.EventBasicInfo; +import alfio.model.support.ReservationInfo; import alfio.util.Json; -import alfio.util.MonetaryUtil; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import java.util.Comparator; @@ -31,7 +29,7 @@ public class PromoCodeUsageResult { private final String promoCode; - private final EventInfo event; + private final EventBasicInfo event; private final List reservations; public PromoCodeUsageResult(@Column("promo_code") String promoCode, @@ -39,7 +37,7 @@ public PromoCodeUsageResult(@Column("promo_code") String promoCode, @Column("event_display_name") String eventDisplayName, @Column("reservations") String reservationsJson) { this.promoCode = promoCode; - this.event = new EventInfo(eventShortName, eventDisplayName); + this.event = new EventBasicInfo(eventShortName, eventDisplayName); List parsed = Json.fromJson(reservationsJson, new TypeReference<>() {}); this.reservations = parsed.stream() .sorted(Comparator.comparing(ReservationInfo::getConfirmationTimestamp)) @@ -50,7 +48,7 @@ public String getPromoCode() { return promoCode; } - public EventInfo getEvent() { + public EventBasicInfo getEvent() { return event; } @@ -58,140 +56,4 @@ public List getReservations() { return reservations; } - public static class ReservationInfo { - private final String id; - private final String invoiceNumber; - private final String firstName; - private final String lastName; - private final String email; - private final PaymentProxy paymentType; - private final Integer finalPriceCts; - private final String currency; - private final String confirmationTimestamp; - private final List tickets; - - @JsonCreator - ReservationInfo(@JsonProperty("id") String id, - @JsonProperty("invoiceNumber") String invoiceNumber, - @JsonProperty("firstName") String firstName, - @JsonProperty("lastName") String lastName, - @JsonProperty("email") String email, - @JsonProperty("paymentType") PaymentProxy paymentType, - @JsonProperty("finalPriceCts") Integer finalPriceCts, - @JsonProperty("currency") String currency, - @JsonProperty("confirmationTimestamp") String confirmationTimestamp, - @JsonProperty("tickets") List tickets) { - this.id = id; - this.invoiceNumber = invoiceNumber; - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - this.paymentType = paymentType; - this.finalPriceCts = finalPriceCts; - this.currency = currency; - this.confirmationTimestamp = confirmationTimestamp; - this.tickets = tickets; - } - - public String getId() { - return id; - } - - public String getInvoiceNumber() { - return invoiceNumber; - } - - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; - } - - public String getEmail() { - return email; - } - - public PaymentProxy getPaymentType() { - return paymentType; - } - - public String getFormattedAmount() { - if (finalPriceCts == null) { - return ""; - } - return MonetaryUtil.formatCents(finalPriceCts, currency); - } - - public String getCurrency() { - return currency; - } - - public String getConfirmationTimestamp() { - return confirmationTimestamp; - } - - public List getTickets() { - return tickets; - } - } - - public static class EventInfo { - private final String shortName; - private final String displayName; - - @JsonCreator - private EventInfo(@JsonProperty("shortName") String shortName, - @JsonProperty("displayName") String displayName) { - this.shortName = shortName; - this.displayName = displayName; - } - - public String getShortName() { - return shortName; - } - - public String getDisplayName() { - return displayName; - } - - public String getPublicIdentifier() { - return getShortName(); - } - } - - public static class TicketInfo { - private final String id; - private final String firstName; - private final String lastName; - private final String type; - - @JsonCreator - private TicketInfo(@JsonProperty("id") String id, - @JsonProperty("firstName") String firstName, - @JsonProperty("lastName") String lastName, - @JsonProperty("type") String type) { - this.id = id; - this.firstName = firstName; - this.lastName = lastName; - this.type = type; - } - - public String getId() { - return id; - } - - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; - } - - public String getType() { - return type; - } - } } diff --git a/src/main/java/alfio/model/ReservationsByEvent.java b/src/main/java/alfio/model/ReservationsByEvent.java new file mode 100644 index 0000000000..30380d1e36 --- /dev/null +++ b/src/main/java/alfio/model/ReservationsByEvent.java @@ -0,0 +1,58 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model; + +import alfio.model.support.ReservationInfo; +import alfio.util.Json; +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.List; + +public class ReservationsByEvent { + + private final int eventId; + private final String eventShortName; + private final String displayName; + private final List reservations; + + public ReservationsByEvent(@Column("event_id") int eventId, + @Column("event_short_name") String eventShortName, + @Column("event_display_name") String displayName, + @Column("reservations") String reservations) { + this.eventId = eventId; + this.eventShortName = eventShortName; + this.displayName = displayName; + this.reservations = Json.fromJson(reservations, new TypeReference<>() {}); + } + + public int getEventId() { + return eventId; + } + + public String getEventShortName() { + return eventShortName; + } + + public String getDisplayName() { + return displayName; + } + + public List getReservations() { + return reservations; + } +} diff --git a/src/main/java/alfio/model/support/EventBasicInfo.java b/src/main/java/alfio/model/support/EventBasicInfo.java new file mode 100644 index 0000000000..0d1947dc0b --- /dev/null +++ b/src/main/java/alfio/model/support/EventBasicInfo.java @@ -0,0 +1,44 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.support; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class EventBasicInfo { + private final String shortName; + private final String displayName; + + @JsonCreator + public EventBasicInfo(@JsonProperty("shortName") String shortName, + @JsonProperty("displayName") String displayName) { + this.shortName = shortName; + this.displayName = displayName; + } + + public String getShortName() { + return shortName; + } + + public String getDisplayName() { + return displayName; + } + + public String getPublicIdentifier() { + return getShortName(); + } +} diff --git a/src/main/java/alfio/model/support/ReservationInfo.java b/src/main/java/alfio/model/support/ReservationInfo.java new file mode 100644 index 0000000000..742238fe4b --- /dev/null +++ b/src/main/java/alfio/model/support/ReservationInfo.java @@ -0,0 +1,103 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.support; + +import alfio.model.transaction.PaymentProxy; +import alfio.util.MonetaryUtil; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class ReservationInfo { + private final String id; + private final String invoiceNumber; + private final String firstName; + private final String lastName; + private final String email; + private final PaymentProxy paymentType; + private final Integer finalPriceCts; + private final String currency; + private final String confirmationTimestamp; + private final List tickets; + + @JsonCreator + ReservationInfo(@JsonProperty("id") String id, + @JsonProperty("invoiceNumber") String invoiceNumber, + @JsonProperty("firstName") String firstName, + @JsonProperty("lastName") String lastName, + @JsonProperty("email") String email, + @JsonProperty("paymentType") PaymentProxy paymentType, + @JsonProperty("finalPriceCts") Integer finalPriceCts, + @JsonProperty("currency") String currency, + @JsonProperty("confirmationTimestamp") String confirmationTimestamp, + @JsonProperty("tickets") List tickets) { + this.id = id; + this.invoiceNumber = invoiceNumber; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.paymentType = paymentType; + this.finalPriceCts = finalPriceCts; + this.currency = currency; + this.confirmationTimestamp = confirmationTimestamp; + this.tickets = tickets; + } + + public String getId() { + return id; + } + + public String getInvoiceNumber() { + return invoiceNumber; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public PaymentProxy getPaymentType() { + return paymentType; + } + + public String getFormattedAmount() { + if (finalPriceCts == null) { + return ""; + } + return MonetaryUtil.formatCents(finalPriceCts, currency); + } + + public String getCurrency() { + return currency; + } + + public String getConfirmationTimestamp() { + return confirmationTimestamp; + } + + public List getTickets() { + return tickets; + } +} diff --git a/src/main/java/alfio/model/support/TicketInfo.java b/src/main/java/alfio/model/support/TicketInfo.java new file mode 100644 index 0000000000..ecd553f106 --- /dev/null +++ b/src/main/java/alfio/model/support/TicketInfo.java @@ -0,0 +1,61 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.support; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class TicketInfo { + private final String id; + private final String firstName; + private final String lastName; + private final String type; + private final String status; + + @JsonCreator + private TicketInfo(@JsonProperty("id") String id, + @JsonProperty("firstName") String firstName, + @JsonProperty("lastName") String lastName, + @JsonProperty("type") String type, + @JsonProperty("status") String status) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.type = type; + this.status = status; + } + + public String getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getType() { + return type; + } + + public String getStatus() { + return status; + } +} diff --git a/src/main/java/alfio/repository/EventRepository.java b/src/main/java/alfio/repository/EventRepository.java index ced06d8839..50cef66a80 100644 --- a/src/main/java/alfio/repository/EventRepository.java +++ b/src/main/java/alfio/repository/EventRepository.java @@ -177,6 +177,8 @@ int updatePrices(@Bind("currency") String currency, @Query("select available_seats from events_statistics where id = :eventId") Integer countExistingTickets(@Bind("eventId") int eventId); + @Query("select count(*) from event") + Integer countEvents(); @Query(value = "update event set status = 'DISABLED' where org_id in (select org_id from j_user_organization where user_id in (:userIds)) returning id", type = QueryType.MODIFYING_WITH_RETURN) List disableEventsForUsers(@Bind("userIds") Collection userIds); diff --git a/src/main/java/alfio/repository/ExportRepository.java b/src/main/java/alfio/repository/ExportRepository.java new file mode 100644 index 0000000000..8d4cbafc35 --- /dev/null +++ b/src/main/java/alfio/repository/ExportRepository.java @@ -0,0 +1,65 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.repository; + +import alfio.model.ReservationsByEvent; +import ch.digitalfondue.npjt.Bind; +import ch.digitalfondue.npjt.Query; +import ch.digitalfondue.npjt.QueryRepository; +import ch.digitalfondue.npjt.QueryType; + +import java.time.ZonedDateTime; +import java.util.List; + +@QueryRepository +public interface ExportRepository { + @Query(type = QueryType.SELECT, value = "with tickets as (" + + " select tr_id, json_agg(jsonb_build_object(" + + " 'id', t_uuid," + + " 'firstName', t_first_name," + + " 'lastName', t_last_name," + + " 'type', tc_name," + + " 'status', t_status" + + " )) items" + + " from checkin_ticket_event_and_category_info" + + " group by 1" + + ")," + + "reservations as (" + + " select e_id," + + " jsonb_agg(jsonb_build_object(" + + " 'id', tr.tr_id," + + " 'invoiceNumber', tr.tr_invoice_number," + + " 'firstName', tr.tr_first_name," + + " 'lastName', tr.tr_last_name," + + " 'email', tr.tr_email_address," + + " 'paymentType', tr.tr_payment_method," + + " 'finalPriceCts', tr.tr_final_price_cts," + + " 'currency', tr.tr_currency_code," + + " 'confirmationTimestamp', to_char(tr.tr_confirmation_ts at time zone 'UTC', 'YYYY-MM-DD') || 'T' || to_char(tr.tr_confirmation_ts at time zone 'UTC', 'HH24:MI:SS.MSZ')," + + " 'tickets', t.items" + + " )) as agg" + + " from checkin_ticket_event_and_category_info tr" + + " join tickets t on tr.tr_id = t.tr_id" + + " where tr_status in ('OFFLINE_PAYMENT', 'DEFERRED_OFFLINE_PAYMENT', 'COMPLETE', 'CANCELLED')" + + " group by 1" + + " )" + + " select distinct c.e_id as event_id, c.e_short_name event_short_name, c.e_display_name event_display_name, r.agg reservations" + + " from checkin_ticket_event_and_category_info c join reservations r on r.e_id = c.e_id" + + " where tr_confirmation_ts between :startTs and :endTs" + + " order by 1") + List allReservationsForInterval(@Bind("startTs") ZonedDateTime from, @Bind("endTs") ZonedDateTime to); +} diff --git a/src/main/java/alfio/util/ExportUtils.java b/src/main/java/alfio/util/ExportUtils.java index 457c4fc520..2cbd66ffb5 100644 --- a/src/main/java/alfio/util/ExportUtils.java +++ b/src/main/java/alfio/util/ExportUtils.java @@ -18,6 +18,7 @@ import ch.digitalfondue.basicxlsx.Cell; import ch.digitalfondue.basicxlsx.StreamingWorkbook; +import ch.digitalfondue.basicxlsx.Style; import com.opencsv.CSVWriter; import javax.servlet.ServletOutputStream; @@ -25,6 +26,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Arrays; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,16 +36,31 @@ public class ExportUtils { private static final int[] BOM_MARKERS = new int[] {0xEF, 0xBB, 0xBF}; + private ExportUtils() {} + public static void exportExcel(String fileName, String sheetName, String[] header, Stream data, HttpServletResponse response) throws IOException { + exportExcel(fileName, response, workbook -> addSheetToWorkbook(sheetName, header, data, workbook, workbook.defineStyle().font().bold(true).build())); + } + + public static void exportExcel(String fileName, + HttpServletResponse response, + Consumer workbookConsumer) throws IOException { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=" + fileName); - try (ServletOutputStream out = response.getOutputStream(); StreamingWorkbook workbook = new StreamingWorkbook(out)) { - var boldFont = workbook.defineStyle().font().bold(true).build(); + workbookConsumer.accept(workbook); + } + } + public static void addSheetToWorkbook(String sheetName, + String[] header, + Stream data, + StreamingWorkbook workbook, + Style headerStyle) { + try { var headerRow = StreamingWorkbook.row(Arrays.stream(header) - .map(v -> Cell.cell(v).withStyle(boldFont)) + .map(v -> Cell.cell(v).withStyle(headerStyle)) .collect(Collectors.toList())); var dataStream = data @@ -51,6 +68,9 @@ public static void exportExcel(String fileName, String sheetName, String[] heade .map(StreamingWorkbook::row); workbook.withSheet(sheetName, Stream.concat(Stream.of(headerRow), dataStream)); + + } catch (IOException e) { + throw new IllegalStateException(e); } } diff --git a/src/main/resources/alfio/db/PGSQL/afterMigrate__016_VIEW_promocode_usage_details.sql b/src/main/resources/alfio/db/PGSQL/afterMigrate__016_VIEW_promocode_usage_details.sql index 5ca84a9b90..7efa613da2 100644 --- a/src/main/resources/alfio/db/PGSQL/afterMigrate__016_VIEW_promocode_usage_details.sql +++ b/src/main/resources/alfio/db/PGSQL/afterMigrate__016_VIEW_promocode_usage_details.sql @@ -21,7 +21,8 @@ with tickets as ( 'id', t.uuid, 'firstName', t.first_name, 'lastName', t.last_name, - 'type', tc.name + 'type', tc.name, + 'status', t.status )) items from ticket t join ticket_category tc on t.category_id = tc.id diff --git a/src/main/resources/alfio/web-templates/admin-index.ms b/src/main/resources/alfio/web-templates/admin-index.ms index 507d1b1043..717f1272ad 100644 --- a/src/main/resources/alfio/web-templates/admin-index.ms +++ b/src/main/resources/alfio/web-templates/admin-index.ms @@ -105,6 +105,7 @@ + diff --git a/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-button.html b/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-button.html new file mode 100644 index 0000000000..edcd153d23 --- /dev/null +++ b/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-button.html @@ -0,0 +1,5 @@ +
+
+ +
+
\ No newline at end of file diff --git a/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-form.html b/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-form.html new file mode 100644 index 0000000000..53cf286bc3 --- /dev/null +++ b/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations-form.html @@ -0,0 +1,43 @@ + diff --git a/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations.js b/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations.js new file mode 100644 index 0000000000..74273d3ced --- /dev/null +++ b/src/main/webapp/resources/js/admin/feature/export-reservations/export-reservations.js @@ -0,0 +1,60 @@ +(function() { + +'use strict'; + + +angular.module('adminApplication').component('exportReservationsButton', { + templateUrl: window.ALFIO_CONTEXT_PATH + '/resources/js/admin/feature/export-reservations/export-reservations-button.html', + controller: exportReservationsButton +}); + + +function exportReservationsButton(EventService, $uibModal) { + var ctrl = this; + + ctrl.$onInit = function() { + EventService.getEventsCount().then(function(response) { + ctrl.eventsCount = response.data; + }); + } + + ctrl.openModal = function() { + $uibModal.open({ + size: 'lg', + templateUrl: window.ALFIO_CONTEXT_PATH + '/resources/js/admin/feature/export-reservations/export-reservations-form.html', + backdrop: 'static', + controllerAs: '$ctrl', + bindToController: true, + controller: function($scope) { + var modalCtrl = this; + modalCtrl.maxDate = moment().endOf('day'); + modalCtrl.searchFrom = null; + modalCtrl.searchTo = null; + modalCtrl.ready = false; + modalCtrl.formattedSearchFrom = null; + modalCtrl.formattedSearchTo = null; + + modalCtrl.close = function() { + $scope.$dismiss(); + } + + $scope.$watch('$ctrl.searchFrom', function(newValue) { + if(newValue) { + modalCtrl.ready = moment(modalCtrl.searchTo).isAfter(moment(newValue)); + modalCtrl.formattedSearchFrom = moment(newValue).format('YYYY-MM-DD'); + } + }); + $scope.$watch('$ctrl.searchTo', function(newValue) { + if(newValue) { + modalCtrl.ready = moment(newValue).isAfter(moment(modalCtrl.searchFrom)); + modalCtrl.formattedSearchTo = moment(newValue).format('YYYY-MM-DD'); + } + }); + } + }); + } +} + +exportReservationsButton.$inject = ['EventService', '$uibModal']; + +})(); \ No newline at end of file diff --git a/src/main/webapp/resources/js/admin/ng-app/admin-application.js b/src/main/webapp/resources/js/admin/ng-app/admin-application.js index c6192bf505..ce7c2c1c8e 100644 --- a/src/main/webapp/resources/js/admin/ng-app/admin-application.js +++ b/src/main/webapp/resources/js/admin/ng-app/admin-application.js @@ -29,6 +29,7 @@ template: ['
', '

Events

', '
', + '', '', '', '
'].join('') diff --git a/src/main/webapp/resources/js/admin/service/service.js b/src/main/webapp/resources/js/admin/service/service.js index bdc2195248..e2db07f6e2 100644 --- a/src/main/webapp/resources/js/admin/service/service.js +++ b/src/main/webapp/resources/js/admin/service/service.js @@ -56,6 +56,9 @@ var service = { data: {}, + getEventsCount: function () { + return $http.get('/admin/api/events-count').error(HttpErrorHandler.handle); + }, getAllEvents : function() { return $http.get('/admin/api/events').error(HttpErrorHandler.handle); }, diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java index ae101a4ddd..10734ffb10 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java @@ -67,6 +67,7 @@ import com.opencsv.CSVReader; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,6 +90,7 @@ import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.security.Principal; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZonedDateTime; import java.util.*; @@ -141,6 +143,7 @@ public abstract class BaseReservationFlowTest extends BaseIntegrationTest { protected final OrganizationDeleter organizationDeleter; protected final PromoCodeDiscountRepository promoCodeDiscountRepository; protected final PromoCodeRequestManager promoCodeRequestManager; + protected final ExportManager exportManager; private Integer additionalServiceId; @@ -289,6 +292,7 @@ protected void testBasicFlow(Supplier contextSupplier) t var context = contextSupplier.get(); ensureConfiguration(context); + Assertions.assertEquals(1, eventManager.getEventsCount()); // check if EVENT_CREATED was logged List extLogs = extensionLogRepository.getPage(null, null, null, 100, 0); @@ -1107,6 +1111,7 @@ protected void testBasicFlow(Supplier contextSupplier) t context.userId )); + checkReservationExport(); //test revert check in assertTrue(checkInApiController.revertCheckIn(context.event.getId(), ticketIdentifier, principal)); @@ -1261,6 +1266,23 @@ protected void testBasicFlow(Supplier contextSupplier) t } + private void checkReservationExport() { + // load all reservations + var now = LocalDate.now(clockProvider.getClock()); + var reservationsByEvent = exportManager.reservationsForInterval(now.minusDays(1), now); + assertEquals(1, reservationsByEvent.size()); + assertEquals(1, reservationsByEvent.get(0).getReservations().size()); + assertEquals(1, reservationsByEvent.get(0).getReservations().get(0).getTickets().size()); + + // ensure that the filtering works as expected + reservationsByEvent = exportManager.reservationsForInterval(now.plusDays(1), now.plusDays(2)); + assertEquals(0, reservationsByEvent.size()); + + // ensure that we get error if the interval is wrong + var wrongFrom = now.plusDays(1); + assertThrows(IllegalArgumentException.class, () -> exportManager.reservationsForInterval(wrongFrom, now)); + } + static void insertExtension(ExtensionService extensionService, String path) throws IOException { insertExtension(extensionService, path, true, true); } diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java index eead9b8f04..4acbc6e6d3 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/CustomTaxPolicyIntegrationTest.java @@ -19,22 +19,13 @@ import alfio.TestConfiguration; import alfio.config.DataSourceConfiguration; import alfio.config.Initializer; -import alfio.controller.IndexController; import alfio.controller.api.ControllerConfiguration; -import alfio.controller.api.admin.AdditionalServiceApiController; -import alfio.controller.api.admin.CheckInApiController; -import alfio.controller.api.admin.EventApiController; -import alfio.controller.api.admin.UsersApiController; -import alfio.controller.api.v1.AttendeeApiController; -import alfio.controller.api.v2.InfoApiController; -import alfio.controller.api.v2.TranslationsApiController; -import alfio.controller.api.v2.user.EventApiV2Controller; import alfio.controller.api.v2.user.ReservationApiV2Controller; -import alfio.controller.api.v2.user.TicketApiV2Controller; import alfio.controller.form.ContactAndTicketsForm; import alfio.controller.form.UpdateTicketOwnerForm; import alfio.extension.ExtensionService; -import alfio.manager.*; +import alfio.manager.EventManager; +import alfio.manager.TicketReservationManager; import alfio.manager.user.UserManager; import alfio.model.Event; import alfio.model.PriceContainer; @@ -44,11 +35,11 @@ import alfio.model.modification.TicketCategoryModification; import alfio.model.modification.TicketReservationModification; import alfio.model.modification.TicketReservationWithOptionalCodeModification; -import alfio.repository.*; -import alfio.repository.audit.ScanAuditRepository; +import alfio.repository.EventRepository; +import alfio.repository.TicketCategoryRepository; +import alfio.repository.TicketRepository; import alfio.repository.system.ConfigurationRepository; import alfio.repository.user.OrganizationRepository; -import alfio.repository.user.UserRepository; import alfio.test.util.IntegrationTestUtil; import alfio.util.ClockProvider; import org.apache.commons.lang3.time.DateUtils; @@ -56,7 +47,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.transaction.annotation.Transactional; @@ -98,38 +88,11 @@ public CustomTaxPolicyIntegrationTest(OrganizationRepository organizationReposit UserManager userManager, ClockProvider clockProvider, ConfigurationRepository configurationRepository, - EventStatisticsManager eventStatisticsManager, TicketCategoryRepository ticketCategoryRepository, - TicketReservationRepository ticketReservationRepository, - EventApiController eventApiController, TicketRepository ticketRepository, - TicketFieldRepository ticketFieldRepository, - AdditionalServiceApiController additionalServiceApiController, - SpecialPriceTokenGenerator specialPriceTokenGenerator, - SpecialPriceRepository specialPriceRepository, - CheckInApiController checkInApiController, - AttendeeApiController attendeeApiController, - UsersApiController usersApiController, - ScanAuditRepository scanAuditRepository, - AuditingRepository auditingRepository, - AdminReservationManager adminReservationManager, TicketReservationManager ticketReservationManager, - InfoApiController infoApiController, - TranslationsApiController translationsApiController, - EventApiV2Controller eventApiV2Controller, ReservationApiV2Controller reservationApiV2Controller, - TicketApiV2Controller ticketApiV2Controller, - IndexController indexController, - NamedParameterJdbcTemplate jdbcTemplate, - ExtensionLogRepository extensionLogRepository, - ExtensionService extensionService, - PollRepository pollRepository, - NotificationManager notificationManager, - UserRepository userRepository, - OrganizationDeleter organizationDeleter, - PromoCodeDiscountRepository promoCodeDiscountRepository, - PromoCodeRequestManager promoCodeRequestManager, - CheckInManager checkInManager) { + ExtensionService extensionService) { this.organizationRepository = organizationRepository; this.userManager = userManager; this.extensionService = extensionService; diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/DiscountedReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/DiscountedReservationFlowIntegrationTest.java index 4144823cd3..18b05ec108 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/DiscountedReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/DiscountedReservationFlowIntegrationTest.java @@ -114,7 +114,8 @@ public DiscountedReservationFlowIntegrationTest(ConfigurationRepository configur PromoCodeDiscountRepository promoCodeDiscountRepository, PromoCodeRequestManager promoCodeRequestManager, OrganizationRepository organizationRepository, - UserManager userManager) { + UserManager userManager, + ExportManager exportManager) { super(configurationRepository, eventManager, eventRepository, @@ -149,7 +150,8 @@ public DiscountedReservationFlowIntegrationTest(ConfigurationRepository configur userRepository, organizationDeleter, promoCodeDiscountRepository, - promoCodeRequestManager); + promoCodeRequestManager, + exportManager); this.organizationRepository = organizationRepository; this.userManager = userManager; } diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/HybridEventReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/HybridEventReservationFlowIntegrationTest.java index 3301130933..6ade090930 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/HybridEventReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/HybridEventReservationFlowIntegrationTest.java @@ -109,7 +109,8 @@ public HybridEventReservationFlowIntegrationTest(OrganizationRepository organiza UserRepository userRepository, OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, - PromoCodeRequestManager promoCodeRequestManager) { + PromoCodeRequestManager promoCodeRequestManager, + ExportManager exportManager) { super(configurationRepository, eventManager, eventRepository, @@ -144,7 +145,8 @@ public HybridEventReservationFlowIntegrationTest(OrganizationRepository organiza userRepository, organizationDeleter, promoCodeDiscountRepository, - promoCodeRequestManager); + promoCodeRequestManager, + exportManager); this.organizationRepository = organizationRepository; this.userManager = userManager; } diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/OnlineEventReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/OnlineEventReservationFlowIntegrationTest.java index 8be5dd3ee7..1b14147ed5 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/OnlineEventReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/OnlineEventReservationFlowIntegrationTest.java @@ -109,7 +109,8 @@ public OnlineEventReservationFlowIntegrationTest(OrganizationRepository organiza UserRepository userRepository, OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, - PromoCodeRequestManager promoCodeRequestManager) { + PromoCodeRequestManager promoCodeRequestManager, + ExportManager exportManager) { super(configurationRepository, eventManager, eventRepository, @@ -144,7 +145,8 @@ public OnlineEventReservationFlowIntegrationTest(OrganizationRepository organiza userRepository, organizationDeleter, promoCodeDiscountRepository, - promoCodeRequestManager); + promoCodeRequestManager, + exportManager); this.organizationRepository = organizationRepository; this.userManager = userManager; } diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowAuthenticatedUserIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowAuthenticatedUserIntegrationTest.java index 02f49ace81..d2e62c8409 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowAuthenticatedUserIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowAuthenticatedUserIntegrationTest.java @@ -120,7 +120,8 @@ public ReservationFlowAuthenticatedUserIntegrationTest(OrganizationRepository or UserApiV2Controller publicUserApiController, OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, - PromoCodeRequestManager promoCodeRequestManager) { + PromoCodeRequestManager promoCodeRequestManager, + ExportManager exportManager) { super(configurationRepository, eventManager, eventRepository, @@ -155,7 +156,8 @@ public ReservationFlowAuthenticatedUserIntegrationTest(OrganizationRepository or userRepository, organizationDeleter, promoCodeDiscountRepository, - promoCodeRequestManager); + promoCodeRequestManager, + exportManager); this.organizationRepository = organizationRepository; this.userManager = userManager; this.publicUserApiController = publicUserApiController; diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java index 9b82d6f473..d6e6a2c9a0 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowIntegrationTest.java @@ -113,7 +113,8 @@ public ReservationFlowIntegrationTest(OrganizationRepository organizationReposit OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, PromoCodeRequestManager promoCodeRequestManager, - CheckInManager checkInManager) { + CheckInManager checkInManager, + ExportManager exportManager) { super(configurationRepository, eventManager, eventRepository, @@ -148,7 +149,8 @@ public ReservationFlowIntegrationTest(OrganizationRepository organizationReposit userRepository, organizationDeleter, promoCodeDiscountRepository, - promoCodeRequestManager); + promoCodeRequestManager, + exportManager); this.organizationRepository = organizationRepository; this.userManager = userManager; this.checkInManager = checkInManager; diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowWithSubscriptionIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowWithSubscriptionIntegrationTest.java index be683210e6..9402f2aaba 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowWithSubscriptionIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/ReservationFlowWithSubscriptionIntegrationTest.java @@ -137,7 +137,8 @@ public ReservationFlowWithSubscriptionIntegrationTest(OrganizationRepository org PlatformTransactionManager platformTransactionManager, OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, - PromoCodeRequestManager promoCodeRequestManager) { + PromoCodeRequestManager promoCodeRequestManager, + ExportManager exportManager) { super(configurationRepository, eventManager, eventRepository, @@ -172,7 +173,8 @@ public ReservationFlowWithSubscriptionIntegrationTest(OrganizationRepository org userRepository, organizationDeleter, promoCodeDiscountRepository, - promoCodeRequestManager); + promoCodeRequestManager, + exportManager); this.organizationRepository = organizationRepository; this.userManager = userManager; this.subscriptionManager = subscriptionManager; diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java index 81e5d2736c..e335de19d6 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/StripeReservationFlowIntegrationTest.java @@ -135,7 +135,8 @@ public StripeReservationFlowIntegrationTest(OrganizationRepository organizationR OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, PromoCodeRequestManager promoCodeRequestManager, - StripePaymentWebhookController stripePaymentWebhookController) { + StripePaymentWebhookController stripePaymentWebhookController, + ExportManager exportManager) { super(configurationRepository, eventManager, eventRepository, @@ -170,7 +171,8 @@ public StripeReservationFlowIntegrationTest(OrganizationRepository organizationR userRepository, organizationDeleter, promoCodeDiscountRepository, - promoCodeRequestManager); + promoCodeRequestManager, + exportManager); this.organizationRepository = organizationRepository; this.userManager = userManager; this.stripePaymentWebhookController = stripePaymentWebhookController; From 9dcc5f4d5f818104e0d0eb20764fd34d27c723e8 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sun, 12 Feb 2023 16:45:18 +0100 Subject: [PATCH 153/218] fix errors after cherry-pick --- .../reservation/BaseReservationFlowTest.java | 4 +- src/test/resources/api/descriptor.json | 469 +++++++++++------- 2 files changed, 300 insertions(+), 173 deletions(-) diff --git a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java index 10734ffb10..0bdaeccb66 100644 --- a/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java +++ b/src/test/java/alfio/controller/api/v2/user/reservation/BaseReservationFlowTest.java @@ -186,7 +186,8 @@ protected BaseReservationFlowTest(ConfigurationRepository configurationRepositor UserRepository userRepository, OrganizationDeleter organizationDeleter, PromoCodeDiscountRepository promoCodeDiscountRepository, - PromoCodeRequestManager promoCodeRequestManager) { + PromoCodeRequestManager promoCodeRequestManager, + ExportManager exportManager) { this.configurationRepository = configurationRepository; this.eventManager = eventManager; this.eventRepository = eventRepository; @@ -222,6 +223,7 @@ protected BaseReservationFlowTest(ConfigurationRepository configurationRepositor this.organizationDeleter = organizationDeleter; this.promoCodeDiscountRepository = promoCodeDiscountRepository; this.promoCodeRequestManager = promoCodeRequestManager; + this.exportManager = exportManager; } private void ensureConfiguration(ReservationFlowContext context) { diff --git a/src/test/resources/api/descriptor.json b/src/test/resources/api/descriptor.json index c0b32be673..62bac4d822 100644 --- a/src/test/resources/api/descriptor.json +++ b/src/test/resources/api/descriptor.json @@ -20003,6 +20003,72 @@ } } }, + "/admin/api/export/reservations" : { + "get" : { + "tags" : [ "export-api-controller" ], + "operationId" : "downloadAllEvents", + "parameters" : [ { + "name" : "from", + "in" : "query", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "to", + "in" : "query", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK" + } + } + } + }, "/admin/api/expired-events" : { "get" : { "tags" : [ "event-api-controller" ], @@ -21606,6 +21672,65 @@ } } }, + "/admin/api/events-count" : { + "get" : { + "tags" : [ "event-api-controller" ], + "operationId" : "getEventsCount", + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "integer", + "format" : "int32" + } + } + } + } + } + } + }, "/admin/api/events-all-languages" : { "get" : { "tags" : [ "event-api-controller" ], @@ -25869,23 +25994,10 @@ "refundedAmount" : { "type" : "string" }, - "notYetPaid" : { - "type" : "boolean" - }, - "vatExempt" : { - "type" : "boolean" - }, - "priceInCents" : { - "type" : "integer", - "format" : "int32" - }, "ticketAmount" : { "type" : "integer", "format" : "int32" }, - "singleTicketOrder" : { - "type" : "boolean" - }, "displayVat" : { "type" : "boolean" }, @@ -25900,6 +26012,19 @@ }, "priceBeforeTaxes" : { "type" : "string" + }, + "singleTicketOrder" : { + "type" : "boolean" + }, + "notYetPaid" : { + "type" : "boolean" + }, + "vatExempt" : { + "type" : "boolean" + }, + "priceInCents" : { + "type" : "integer", + "format" : "int32" } } }, @@ -26093,13 +26218,13 @@ "valid" : { "type" : "boolean" }, - "formattedValidityFrom" : { + "formattedValidityTo" : { "type" : "string" }, - "pin" : { + "formattedValidityFrom" : { "type" : "string" }, - "formattedValidityTo" : { + "pin" : { "type" : "string" } } @@ -26589,6 +26714,10 @@ "currencyCode" : { "type" : "string" }, + "status" : { + "type" : "string", + "enum" : [ "PENDING", "IN_PAYMENT", "EXTERNAL_PROCESSING_PAYMENT", "WAITING_EXTERNAL_CONFIRMATION", "OFFLINE_PAYMENT", "DEFERRED_OFFLINE_PAYMENT", "COMPLETE", "STUCK", "CANCELLED", "CREDIT_NOTE_ISSUED" ] + }, "stuck" : { "type" : "boolean" }, @@ -26615,14 +26744,22 @@ "type" : "string", "format" : "date-time" }, - "status" : { - "type" : "string", - "enum" : [ "PENDING", "IN_PAYMENT", "EXTERNAL_PROCESSING_PAYMENT", "WAITING_EXTERNAL_CONFIRMATION", "OFFLINE_PAYMENT", "DEFERRED_OFFLINE_PAYMENT", "COMPLETE", "STUCK", "CANCELLED", "CREDIT_NOTE_ISSUED" ] - }, "promoCodeDiscountId" : { "type" : "integer", "format" : "int32" }, + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "hasInvoiceNumber" : { + "type" : "boolean" + }, + "invoiceNumber" : { + "type" : "string" + }, "paymentMethod" : { "type" : "string", "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] @@ -26631,11 +26768,18 @@ "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "hasInvoiceNumber" : { - "type" : "boolean" + "srcPriceCts" : { + "type" : "integer", + "format" : "int32" }, - "invoiceNumber" : { - "type" : "string" + "finalPrice" : { + "type" : "number" + }, + "vat" : { + "type" : "number" + }, + "appliedDiscount" : { + "type" : "number" }, "finalPriceCts" : { "type" : "integer", @@ -26658,25 +26802,6 @@ "invoiceRequested" : { "type" : "boolean" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "srcPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "finalPrice" : { - "type" : "number" - }, - "vat" : { - "type" : "number" - }, - "appliedDiscount" : { - "type" : "number" - }, "pendingOfflinePayment" : { "type" : "boolean" }, @@ -28464,16 +28589,16 @@ "currencyCode" : { "type" : "string" }, + "status" : { + "type" : "string", + "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] + }, "formattedNetPrice" : { "type" : "string" }, "extReference" : { "type" : "string" }, - "status" : { - "type" : "string", - "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] - }, "tags" : { "type" : "array", "items" : { @@ -28487,33 +28612,33 @@ "type" : "integer", "format" : "int32" }, + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "subscriptionId" : { + "type" : "string", + "format" : "uuid" + }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "finalPriceCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "vatCts" : { + "finalPriceCts" : { "type" : "integer", "format" : "int32" }, - "discountCts" : { + "vatCts" : { "type" : "integer", "format" : "int32" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "subscriptionId" : { - "type" : "string", - "format" : "uuid" - }, - "srcPriceCts" : { + "discountCts" : { "type" : "integer", "format" : "int32" }, @@ -29787,16 +29912,16 @@ "currencyCode" : { "type" : "string" }, + "status" : { + "type" : "string", + "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] + }, "formattedNetPrice" : { "type" : "string" }, "extReference" : { "type" : "string" }, - "status" : { - "type" : "string", - "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] - }, "tags" : { "type" : "array", "items" : { @@ -29810,33 +29935,33 @@ "type" : "integer", "format" : "int32" }, + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "subscriptionId" : { + "type" : "string", + "format" : "uuid" + }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "finalPriceCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "vatCts" : { + "finalPriceCts" : { "type" : "integer", "format" : "int32" }, - "discountCts" : { + "vatCts" : { "type" : "integer", "format" : "int32" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "subscriptionId" : { - "type" : "string", - "format" : "uuid" - }, - "srcPriceCts" : { + "discountCts" : { "type" : "integer", "format" : "int32" }, @@ -31726,6 +31851,18 @@ "displayName" : { "type" : "string" }, + "titleAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, + "descriptionAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, "publicIdentifier" : { "type" : "string" }, @@ -31752,18 +31889,6 @@ "freeOfCharge" : { "type" : "boolean" }, - "titleAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, - "descriptionAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, "fileBlobIdIsPresent" : { "type" : "boolean" }, @@ -31864,19 +31989,19 @@ "currencyCode" : { "type" : "string" }, + "status" : { + "type" : "string", + "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] + }, + "stuck" : { + "type" : "boolean" + }, "formattedNetPrice" : { "type" : "string" }, "extReference" : { "type" : "string" }, - "stuck" : { - "type" : "boolean" - }, - "status" : { - "type" : "string", - "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] - }, "tags" : { "type" : "array", "items" : { @@ -31893,22 +32018,6 @@ "type" : "integer", "format" : "int32" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, - "finalPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "vatCts" : { - "type" : "integer", - "format" : "int32" - }, - "discountCts" : { - "type" : "integer", - "format" : "int32" - }, "firstName" : { "type" : "string" }, @@ -31919,6 +32028,10 @@ "type" : "string", "format" : "uuid" }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -31926,6 +32039,18 @@ "finalPrice" : { "type" : "number" }, + "finalPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatCts" : { + "type" : "integer", + "format" : "int32" + }, + "discountCts" : { + "type" : "integer", + "format" : "int32" + }, "email" : { "type" : "string" }, @@ -32112,16 +32237,16 @@ "currencyCode" : { "type" : "string" }, + "status" : { + "type" : "string", + "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] + }, "formattedNetPrice" : { "type" : "string" }, "extReference" : { "type" : "string" }, - "status" : { - "type" : "string", - "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] - }, "tags" : { "type" : "array", "items" : { @@ -32135,33 +32260,33 @@ "type" : "integer", "format" : "int32" }, + "firstName" : { + "type" : "string" + }, + "lastName" : { + "type" : "string" + }, + "subscriptionId" : { + "type" : "string", + "format" : "uuid" + }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "finalPriceCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "vatCts" : { + "finalPriceCts" : { "type" : "integer", "format" : "int32" }, - "discountCts" : { + "vatCts" : { "type" : "integer", "format" : "int32" }, - "firstName" : { - "type" : "string" - }, - "lastName" : { - "type" : "string" - }, - "subscriptionId" : { - "type" : "string", - "format" : "uuid" - }, - "srcPriceCts" : { + "discountCts" : { "type" : "integer", "format" : "int32" }, @@ -32806,7 +32931,7 @@ } } }, - "EventInfo" : { + "EventBasicInfo" : { "type" : "object", "properties" : { "shortName" : { @@ -32827,7 +32952,7 @@ "type" : "string" }, "event" : { - "$ref" : "#/components/schemas/EventInfo" + "$ref" : "#/components/schemas/EventBasicInfo" }, "reservations" : { "type" : "array", @@ -32916,6 +33041,15 @@ "description" : { "type" : "string" }, + "formattedStart" : { + "type" : "string" + }, + "formattedEnd" : { + "type" : "string" + }, + "formattedDiscountAmount" : { + "type" : "string" + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -32974,15 +33108,6 @@ }, "fixedAmount" : { "type" : "boolean" - }, - "formattedStart" : { - "type" : "string" - }, - "formattedEnd" : { - "type" : "string" - }, - "formattedDiscountAmount" : { - "type" : "string" } } }, @@ -33269,9 +33394,32 @@ "type" : "string", "enum" : [ "DRAFT", "PUBLIC", "DISABLED" ] }, + "notSoldTickets" : { + "type" : "integer", + "format" : "int32" + }, + "soldTickets" : { + "type" : "integer", + "format" : "int32" + }, + "pendingTickets" : { + "type" : "integer", + "format" : "int32" + }, + "dynamicAllocation" : { + "type" : "integer", + "format" : "int32" + }, + "releasedTickets" : { + "type" : "integer", + "format" : "int32" + }, "shortName" : { "type" : "string" }, + "formattedEnd" : { + "type" : "string" + }, "organizationId" : { "type" : "integer", "format" : "int32" @@ -33301,29 +33449,6 @@ "expired" : { "type" : "boolean" }, - "notSoldTickets" : { - "type" : "integer", - "format" : "int32" - }, - "soldTickets" : { - "type" : "integer", - "format" : "int32" - }, - "pendingTickets" : { - "type" : "integer", - "format" : "int32" - }, - "dynamicAllocation" : { - "type" : "integer", - "format" : "int32" - }, - "releasedTickets" : { - "type" : "integer", - "format" : "int32" - }, - "formattedEnd" : { - "type" : "string" - }, "warningNeeded" : { "type" : "boolean" }, @@ -33637,6 +33762,12 @@ "type" : "integer", "format" : "int32" }, + "disabledValues" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, "minLength" : { "type" : "integer", "format" : "int32" @@ -33695,12 +33826,6 @@ "type" : "integer", "format" : "int32" } - }, - "disabledValues" : { - "type" : "array", - "items" : { - "type" : "string" - } } } }, From debbb9dc86f2f38089d2a3dcc53a8af212c27587 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sun, 12 Feb 2023 19:07:17 +0100 Subject: [PATCH 154/218] add the possibility to hide PIN on subscriptions (cherry-picked from 606ab665e76c1e8b2c0402dea386946f5bfafbba) --- .../api/v2/model/ReservationInfo.java | 3 +- .../v2/user/ReservationApiV2Controller.java | 8 +++- .../java/alfio/manager/ExtensionManager.java | 2 +- .../alfio/manager/NotificationManager.java | 7 ++-- .../manager/TicketReservationManager.java | 2 +- ...ubscriptionReservationCreationRequest.java | 13 +++++- .../SubscriptionConfiguration.java | 42 +++++++++++++++++++ .../model/metadata/SubscriptionMetadata.java | 15 ++++++- .../java/alfio/util/TemplateResource.java | 4 +- .../resources/alfio/templates/subscription.ms | 3 +- .../v1/ReservationApiV1ControllerTest.java | 3 +- 11 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionConfiguration.java diff --git a/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java b/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java index 945be99eed..126f9e9ca6 100644 --- a/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java @@ -23,6 +23,7 @@ import alfio.model.SummaryRow.SummaryType; import alfio.model.TicketCategory; import alfio.model.TicketReservation.TicketReservationStatus; +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; import alfio.model.subscription.UsageDetails; import alfio.model.transaction.PaymentMethod; import alfio.model.transaction.PaymentProxy; @@ -178,7 +179,7 @@ public record ReservationInfoOrderSummaryRow(String name, } - public record SubscriptionInfo(UUID id, String pin, UsageDetails usageDetails, SubscriptionOwner owner) { + public record SubscriptionInfo(UUID id, String pin, UsageDetails usageDetails, SubscriptionOwner owner, SubscriptionConfiguration configuration) { } diff --git a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java index 41da144c66..68be71bd46 100644 --- a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java @@ -39,6 +39,7 @@ import alfio.manager.user.PublicUserManager; import alfio.model.*; import alfio.model.PurchaseContext.PurchaseContextType; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.subscription.UsageDetails; import alfio.model.system.ConfigurationKeys; import alfio.model.transaction.*; @@ -72,6 +73,7 @@ import static alfio.model.system.ConfigurationKeys.ENABLE_ITALY_E_INVOICING; import static alfio.model.system.ConfigurationKeys.FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION; +import static java.util.Objects.requireNonNullElseGet; import static java.util.stream.Collectors.toMap; @RestController @@ -219,14 +221,16 @@ public ResponseEntity getReservationInfo(@PathVariable("reserva List subscriptionInfos = null; if (purchaseContext.ofType(PurchaseContextType.subscription)) { subscriptionInfos = subscriptionRepository.findSubscriptionsByReservationId(reservationId).stream() - .limit(1) // since we support only one subscription for now, it make sense to limit the result to avoid N+1 + .limit(1) // since we support only one subscription for now, it makes sense to limit the result to avoid N+1 .map(s -> { int usageCount = ticketRepository.countSubscriptionUsage(s.getId(), null); + var metadata = requireNonNullElseGet(subscriptionRepository.getSubscriptionMetadata(s.getId()), SubscriptionMetadata::empty); return new ReservationInfo.SubscriptionInfo( s.getStatus() == AllocationStatus.ACQUIRED ? s.getId() : null, s.getStatus() == AllocationStatus.ACQUIRED ? s.getPin() : null, UsageDetails.fromSubscription(s, usageCount), - new ReservationInfo.SubscriptionOwner(s.getFirstName(), s.getLastName(), s.getEmail())); + new ReservationInfo.SubscriptionOwner(s.getFirstName(), s.getLastName(), s.getEmail()), + metadata.getConfiguration()); }) .collect(Collectors.toList()); } diff --git a/src/main/java/alfio/manager/ExtensionManager.java b/src/main/java/alfio/manager/ExtensionManager.java index f81d7e5818..0724503c46 100644 --- a/src/main/java/alfio/manager/ExtensionManager.java +++ b/src/main/java/alfio/manager/ExtensionManager.java @@ -550,7 +550,7 @@ public Optional handleSubscriptionAssignmentMetadata(Subsc SubscriptionMetadata subscriptionMetadata) { var context = new HashMap(); context.put("subscription", subscription); - context.put("metadata", subscriptionMetadata); + context.put("metadata", Objects.requireNonNullElseGet(subscriptionMetadata, SubscriptionMetadata::empty)); context.put("subscriptionDescriptor", descriptor); return Optional.ofNullable(syncCall(ExtensionEvent.SUBSCRIPTION_ASSIGNED_GENERATE_METADATA, descriptor, context, SubscriptionMetadata.class, false)); } diff --git a/src/main/java/alfio/manager/NotificationManager.java b/src/main/java/alfio/manager/NotificationManager.java index cc6949ecc3..2b382c53c0 100644 --- a/src/main/java/alfio/manager/NotificationManager.java +++ b/src/main/java/alfio/manager/NotificationManager.java @@ -131,7 +131,7 @@ public NotificationManager(Mailer mailer, attachmentTransformer.put(Mailer.AttachmentIdentifier.PASSBOOK, passKitManager::getPass); Function> retrieveFieldValues = EventUtil.retrieveFieldValues(ticketRepository, ticketFieldRepository, additionalServiceItemRepository); attachmentTransformer.put(Mailer.AttachmentIdentifier.TICKET_PDF, generateTicketPDF(eventRepository, organizationRepository, configurationManager, fileUploadManager, templateManager, ticketReservationRepository, retrieveFieldValues, extensionManager, ticketRepository, subscriptionRepository)); - attachmentTransformer.put(Mailer.AttachmentIdentifier.SUBSCRIPTION_PDF, generateSubscriptionPDF(organizationRepository, configurationManager, fileUploadManager, templateManager, ticketReservationRepository, extensionManager, subscriptionRepository, messageSourceManager)); + attachmentTransformer.put(Mailer.AttachmentIdentifier.SUBSCRIPTION_PDF, generateSubscriptionPDF(organizationRepository, configurationManager, fileUploadManager, templateManager, ticketReservationRepository, extensionManager, subscriptionRepository)); } private static Function, byte[]> generateTicketPDF(EventRepository eventRepository, @@ -513,8 +513,7 @@ private static Function, byte[]> generateSubscriptionPDF(Org TemplateManager templateManager, TicketReservationRepository ticketReservationRepository, ExtensionManager extensionManager, - SubscriptionRepository subscriptionRepository, - MessageSourceManager messageSourceManager) { + SubscriptionRepository subscriptionRepository) { return model -> { ByteArrayOutputStream baos = new ByteArrayOutputStream(); var subscriptionId = UUID.fromString(model.get("subscriptionId")); @@ -523,7 +522,7 @@ private static Function, byte[]> generateSubscriptionPDF(Org var subscriptionDescriptor = subscriptionRepository.findDescriptorBySubscriptionId(subscriptionId); var reservation = ticketReservationRepository.findReservationById(subscription.getReservationId()); Organization organization = organizationRepository.getById(subscriptionDescriptor.getOrganizationId()); - var metadata = subscriptionRepository.getSubscriptionMetadata(subscription.getId()); + var metadata = Objects.requireNonNullElseGet(subscriptionRepository.getSubscriptionMetadata(subscription.getId()), SubscriptionMetadata::empty); TemplateProcessor.renderSubscriptionPDF(subscription, LocaleUtil.forLanguageTag(reservation.getUserLanguage()), subscriptionDescriptor, diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index f8e0b36b92..2a2c10f92e 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -2796,7 +2796,7 @@ public Optional createSubscriptionReservation(SubscriptionDescriptor sub Locale locale, BindingResult bindingResult, Principal principal) { - return createSubscriptionReservation(subscriptionDescriptor, locale, bindingResult, principal, null); + return createSubscriptionReservation(subscriptionDescriptor, locale, bindingResult, principal, SubscriptionMetadata.empty()); } public Optional createSubscriptionReservation(SubscriptionDescriptor subscriptionDescriptor, diff --git a/src/main/java/alfio/model/api/v1/admin/SubscriptionReservationCreationRequest.java b/src/main/java/alfio/model/api/v1/admin/SubscriptionReservationCreationRequest.java index 34afb8982f..9b15c94e53 100644 --- a/src/main/java/alfio/model/api/v1/admin/SubscriptionReservationCreationRequest.java +++ b/src/main/java/alfio/model/api/v1/admin/SubscriptionReservationCreationRequest.java @@ -16,27 +16,32 @@ */ package alfio.model.api.v1.admin; +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; import alfio.model.metadata.SubscriptionMetadata; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Map; +import java.util.Objects; public class SubscriptionReservationCreationRequest implements ReservationAPICreationRequest { private final Map metadata; private final ReservationUser user; private final String language; private final ReservationConfiguration reservationConfiguration; + private final SubscriptionConfiguration subscriptionConfiguration; @JsonCreator public SubscriptionReservationCreationRequest(@JsonProperty("metadata") Map metadata, @JsonProperty("user") ReservationUser user, @JsonProperty("language") String language, - @JsonProperty("reservationConfiguration") ReservationConfiguration reservationConfiguration) { + @JsonProperty("reservationConfiguration") ReservationConfiguration reservationConfiguration, + @JsonProperty("subscriptionConfiguration") SubscriptionConfiguration subscriptionConfiguration) { this.metadata = metadata; this.user = user; this.language = language; this.reservationConfiguration = reservationConfiguration; + this.subscriptionConfiguration = Objects.requireNonNullElseGet(subscriptionConfiguration, SubscriptionConfiguration::defaultConfiguration); } public Map getMetadata() { @@ -58,9 +63,13 @@ public ReservationConfiguration getReservationConfiguration() { return reservationConfiguration; } + public SubscriptionConfiguration getSubscriptionConfiguration() { + return subscriptionConfiguration; + } + public SubscriptionMetadata getMetadataOrNull() { if (metadata != null && !metadata.isEmpty()) { - return new SubscriptionMetadata(metadata); + return new SubscriptionMetadata(metadata, subscriptionConfiguration); } return null; } diff --git a/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionConfiguration.java b/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionConfiguration.java new file mode 100644 index 0000000000..c1a05e5ad0 --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionConfiguration.java @@ -0,0 +1,42 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin.subscription; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Objects; + +public class SubscriptionConfiguration { + /** + * Display PIN information on reservation page and PDF. Default is {@code true} + */ + private final boolean displayPin; + + @JsonCreator + public SubscriptionConfiguration(@JsonProperty("displayPin") Boolean displayPin) { + this.displayPin = Objects.requireNonNullElse(displayPin, true); + } + + public boolean isDisplayPin() { + return displayPin; + } + + public static SubscriptionConfiguration defaultConfiguration() { + return new SubscriptionConfiguration(true); + } +} diff --git a/src/main/java/alfio/model/metadata/SubscriptionMetadata.java b/src/main/java/alfio/model/metadata/SubscriptionMetadata.java index bdf0506f93..ef3fc9007b 100644 --- a/src/main/java/alfio/model/metadata/SubscriptionMetadata.java +++ b/src/main/java/alfio/model/metadata/SubscriptionMetadata.java @@ -16,6 +16,7 @@ */ package alfio.model.metadata; +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; @@ -25,13 +26,25 @@ public class SubscriptionMetadata { private final Map properties; + private final SubscriptionConfiguration configuration; @JsonCreator - public SubscriptionMetadata(@JsonProperty("properties") Map properties) { + public SubscriptionMetadata(@JsonProperty("properties") Map properties, + @JsonProperty("configuration") SubscriptionConfiguration configuration) { this.properties = Objects.requireNonNullElse(properties, Map.of()); + this.configuration = Objects.requireNonNullElseGet(configuration, SubscriptionConfiguration::defaultConfiguration); } + public Map getProperties() { return properties; } + + public SubscriptionConfiguration getConfiguration() { + return configuration; + } + + public static SubscriptionMetadata empty() { + return new SubscriptionMetadata(null, null); + } } diff --git a/src/main/java/alfio/util/TemplateResource.java b/src/main/java/alfio/util/TemplateResource.java index 4c634ac4bd..ca1ea12280 100644 --- a/src/main/java/alfio/util/TemplateResource.java +++ b/src/main/java/alfio/util/TemplateResource.java @@ -18,6 +18,7 @@ import alfio.model.*; import alfio.model.PurchaseContext.PurchaseContextType; +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; import alfio.model.metadata.SubscriptionMetadata; import alfio.model.modification.SendCodeModification; import alfio.model.subscription.Subscription; @@ -236,7 +237,7 @@ public Map prepareSampleModel(Organization organization, Purchas ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)), subscriptionDescriptor.getTimeZone() ); - var subscriptionMetadata = new SubscriptionMetadata(Map.of("key", "value")); + var subscriptionMetadata = new SubscriptionMetadata(Map.of("key", "value"), SubscriptionConfiguration.defaultConfiguration()); return buildModelForSubscriptionPDF(subscription, subscriptionDescriptor, organization, subscriptionMetadata, imageData, RESERVATION_ID_VALUE, Locale.ENGLISH, sampleTicketReservation(zoneId)); } }, @@ -626,6 +627,7 @@ public static Map buildModelForSubscriptionPDF(Subscription subs model.put("reservation", reservation); model.put(RESERVATION_ID, reservationId); model.put(METADATA_ATTRIBUTES_KEY, metadata.getProperties()); + model.put("displayPin", metadata.getConfiguration().isDisplayPin()); imageData.ifPresent(iData -> { model.put("logo", iData.eventImage); model.put("imageWidth", iData.imageWidth); diff --git a/src/main/resources/alfio/templates/subscription.ms b/src/main/resources/alfio/templates/subscription.ms index 23dce3cca0..4c2b35c744 100644 --- a/src/main/resources/alfio/templates/subscription.ms +++ b/src/main/resources/alfio/templates/subscription.ms @@ -44,13 +44,14 @@

{{#subscriptionDescription}}{{/subscriptionDescription}}

+ {{#displayPin}}

{{#i18n}}reservation-page-complete.subscription.pin-description{{/i18n}}

{{subscription.pin}}

{{#i18n}}reservation-page-complete.subscription.id-description{{/i18n}}

{{subscription.id}}

-

+ {{/displayPin}} diff --git a/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java b/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java index 4ac134d20e..9ff66588de 100644 --- a/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java +++ b/src/test/java/alfio/controller/api/v1/ReservationApiV1ControllerTest.java @@ -420,7 +420,8 @@ void createSubscriptionWithMetadata() { var reservationRequest = new SubscriptionReservationCreationRequest(Map.of("key", "value"), new ReservationUser("test@test.org", "Test", "Test1", "test@test.org", null), "en", - new ReservationConfiguration(true)); + new ReservationConfiguration(true), + null); var reservationResponse = controller.createSubscriptionReservation(descriptorId, reservationRequest, principal); assertTrue(reservationResponse.getStatusCode().is2xxSuccessful()); assertNotNull(reservationResponse.getBody()); From 283f14a2dd2e1382f166e044670fb4bee7f0a585 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Sun, 12 Feb 2023 19:21:29 +0100 Subject: [PATCH 155/218] fix errors after cherry-pick --- .../alfio/manager/NotificationManager.java | 1 + src/test/resources/api/descriptor.json | 397 +++++++++--------- 2 files changed, 208 insertions(+), 190 deletions(-) diff --git a/src/main/java/alfio/manager/NotificationManager.java b/src/main/java/alfio/manager/NotificationManager.java index 2b382c53c0..d51bedb639 100644 --- a/src/main/java/alfio/manager/NotificationManager.java +++ b/src/main/java/alfio/manager/NotificationManager.java @@ -26,6 +26,7 @@ import alfio.manager.system.Mailer; import alfio.model.*; import alfio.model.PurchaseContext.PurchaseContextType; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.subscription.SubscriptionDescriptor; import alfio.model.system.ConfigurationKeys; import alfio.model.user.Organization; diff --git a/src/test/resources/api/descriptor.json b/src/test/resources/api/descriptor.json index 62bac4d822..2188454d62 100644 --- a/src/test/resources/api/descriptor.json +++ b/src/test/resources/api/descriptor.json @@ -25994,10 +25994,23 @@ "refundedAmount" : { "type" : "string" }, + "notYetPaid" : { + "type" : "boolean" + }, + "vatExempt" : { + "type" : "boolean" + }, + "priceInCents" : { + "type" : "integer", + "format" : "int32" + }, "ticketAmount" : { "type" : "integer", "format" : "int32" }, + "singleTicketOrder" : { + "type" : "boolean" + }, "displayVat" : { "type" : "boolean" }, @@ -26012,19 +26025,6 @@ }, "priceBeforeTaxes" : { "type" : "string" - }, - "singleTicketOrder" : { - "type" : "boolean" - }, - "notYetPaid" : { - "type" : "boolean" - }, - "vatExempt" : { - "type" : "boolean" - }, - "priceInCents" : { - "type" : "integer", - "format" : "int32" } } }, @@ -26218,13 +26218,13 @@ "valid" : { "type" : "boolean" }, - "formattedValidityTo" : { + "pin" : { "type" : "string" }, - "formattedValidityFrom" : { + "formattedValidityTo" : { "type" : "string" }, - "pin" : { + "formattedValidityFrom" : { "type" : "string" } } @@ -26377,9 +26377,6 @@ "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, "assigned" : { "type" : "boolean" }, @@ -26388,6 +26385,9 @@ }, "formattedFinalPrice" : { "type" : "string" + }, + "formattedNetPrice" : { + "type" : "string" } } }, @@ -26748,6 +26748,31 @@ "type" : "integer", "format" : "int32" }, + "finalPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatCts" : { + "type" : "integer", + "format" : "int32" + }, + "discountCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatNr" : { + "type" : "string" + }, + "vatCountryCode" : { + "type" : "string" + }, + "invoiceRequested" : { + "type" : "boolean" + }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "firstName" : { "type" : "string" }, @@ -26764,10 +26789,6 @@ "type" : "string", "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -26781,27 +26802,6 @@ "appliedDiscount" : { "type" : "number" }, - "finalPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "vatCts" : { - "type" : "integer", - "format" : "int32" - }, - "discountCts" : { - "type" : "integer", - "format" : "int32" - }, - "vatNr" : { - "type" : "string" - }, - "vatCountryCode" : { - "type" : "string" - }, - "invoiceRequested" : { - "type" : "boolean" - }, "pendingOfflinePayment" : { "type" : "boolean" }, @@ -28092,6 +28092,14 @@ } } }, + "SubscriptionConfiguration" : { + "type" : "object", + "properties" : { + "displayPin" : { + "type" : "boolean" + } + } + }, "SubscriptionMetadata" : { "type" : "object", "properties" : { @@ -28100,6 +28108,9 @@ "additionalProperties" : { "type" : "string" } + }, + "configuration" : { + "$ref" : "#/components/schemas/SubscriptionConfiguration" } } }, @@ -28121,6 +28132,9 @@ "reservationConfiguration" : { "$ref" : "#/components/schemas/ReservationConfiguration" }, + "subscriptionConfiguration" : { + "$ref" : "#/components/schemas/SubscriptionConfiguration" + }, "metadataOrNull" : { "$ref" : "#/components/schemas/SubscriptionMetadata" } @@ -28593,12 +28607,6 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "tags" : { "type" : "array", "items" : { @@ -28608,6 +28616,22 @@ "assigned" : { "type" : "boolean" }, + "finalPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatCts" : { + "type" : "integer", + "format" : "int32" + }, + "discountCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -28622,26 +28646,10 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "finalPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "vatCts" : { - "type" : "integer", - "format" : "int32" - }, - "discountCts" : { - "type" : "integer", - "format" : "int32" - }, "email" : { "type" : "string" }, @@ -28671,6 +28679,12 @@ "formattedFinalPrice" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "categoryName" : { "type" : "string" } @@ -29916,12 +29930,6 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "tags" : { "type" : "array", "items" : { @@ -29931,6 +29939,22 @@ "assigned" : { "type" : "boolean" }, + "finalPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatCts" : { + "type" : "integer", + "format" : "int32" + }, + "discountCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -29945,26 +29969,10 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "finalPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "vatCts" : { - "type" : "integer", - "format" : "int32" - }, - "discountCts" : { - "type" : "integer", - "format" : "int32" - }, "email" : { "type" : "string" }, @@ -29993,6 +30001,12 @@ }, "formattedFinalPrice" : { "type" : "string" + }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" } } }, @@ -31036,6 +31050,9 @@ }, "owner" : { "$ref" : "#/components/schemas/SubscriptionOwner" + }, + "configuration" : { + "$ref" : "#/components/schemas/SubscriptionConfiguration" } } }, @@ -31851,18 +31868,6 @@ "displayName" : { "type" : "string" }, - "titleAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, - "descriptionAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, "publicIdentifier" : { "type" : "string" }, @@ -31889,6 +31894,18 @@ "freeOfCharge" : { "type" : "boolean" }, + "titleAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, + "descriptionAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, "fileBlobIdIsPresent" : { "type" : "boolean" }, @@ -31993,27 +32010,37 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "stuck" : { - "type" : "boolean" - }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "tags" : { "type" : "array", "items" : { "type" : "string" } }, + "stuck" : { + "type" : "boolean" + }, "assigned" : { "type" : "boolean" }, "transaction" : { "$ref" : "#/components/schemas/Transaction" }, + "finalPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatCts" : { + "type" : "integer", + "format" : "int32" + }, + "discountCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -32028,10 +32055,6 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" @@ -32039,18 +32062,6 @@ "finalPrice" : { "type" : "number" }, - "finalPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "vatCts" : { - "type" : "integer", - "format" : "int32" - }, - "discountCts" : { - "type" : "integer", - "format" : "int32" - }, "email" : { "type" : "string" }, @@ -32080,6 +32091,12 @@ "formattedFinalPrice" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "transactionTimestamp" : { "type" : "string", "format" : "date-time" @@ -32241,12 +32258,6 @@ "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "tags" : { "type" : "array", "items" : { @@ -32256,6 +32267,22 @@ "assigned" : { "type" : "boolean" }, + "finalPriceCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatCts" : { + "type" : "integer", + "format" : "int32" + }, + "discountCts" : { + "type" : "integer", + "format" : "int32" + }, + "vatStatus" : { + "type" : "string", + "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] + }, "eventId" : { "type" : "integer", "format" : "int32" @@ -32270,26 +32297,10 @@ "type" : "string", "format" : "uuid" }, - "vatStatus" : { - "type" : "string", - "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] - }, "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "finalPriceCts" : { - "type" : "integer", - "format" : "int32" - }, - "vatCts" : { - "type" : "integer", - "format" : "int32" - }, - "discountCts" : { - "type" : "integer", - "format" : "int32" - }, "email" : { "type" : "string" }, @@ -32319,6 +32330,12 @@ "formattedFinalPrice" : { "type" : "string" }, + "formattedNetPrice" : { + "type" : "string" + }, + "extReference" : { + "type" : "string" + }, "additionalFields" : { "type" : "object", "additionalProperties" : { @@ -33041,15 +33058,6 @@ "description" : { "type" : "string" }, - "formattedStart" : { - "type" : "string" - }, - "formattedEnd" : { - "type" : "string" - }, - "formattedDiscountAmount" : { - "type" : "string" - }, "eventId" : { "type" : "integer", "format" : "int32" @@ -33108,6 +33116,15 @@ }, "fixedAmount" : { "type" : "boolean" + }, + "formattedStart" : { + "type" : "string" + }, + "formattedEnd" : { + "type" : "string" + }, + "formattedDiscountAmount" : { + "type" : "string" } } }, @@ -33394,32 +33411,9 @@ "type" : "string", "enum" : [ "DRAFT", "PUBLIC", "DISABLED" ] }, - "notSoldTickets" : { - "type" : "integer", - "format" : "int32" - }, - "soldTickets" : { - "type" : "integer", - "format" : "int32" - }, - "pendingTickets" : { - "type" : "integer", - "format" : "int32" - }, - "dynamicAllocation" : { - "type" : "integer", - "format" : "int32" - }, - "releasedTickets" : { - "type" : "integer", - "format" : "int32" - }, "shortName" : { "type" : "string" }, - "formattedEnd" : { - "type" : "string" - }, "organizationId" : { "type" : "integer", "format" : "int32" @@ -33434,21 +33428,44 @@ "fileBlobId" : { "type" : "string" }, - "notAllocatedTickets" : { + "checkedInTickets" : { "type" : "integer", "format" : "int32" }, - "availableSeats" : { + "notAllocatedTickets" : { "type" : "integer", "format" : "int32" }, - "checkedInTickets" : { + "availableSeats" : { "type" : "integer", "format" : "int32" }, "expired" : { "type" : "boolean" }, + "notSoldTickets" : { + "type" : "integer", + "format" : "int32" + }, + "soldTickets" : { + "type" : "integer", + "format" : "int32" + }, + "pendingTickets" : { + "type" : "integer", + "format" : "int32" + }, + "dynamicAllocation" : { + "type" : "integer", + "format" : "int32" + }, + "releasedTickets" : { + "type" : "integer", + "format" : "int32" + }, + "formattedEnd" : { + "type" : "string" + }, "warningNeeded" : { "type" : "boolean" }, @@ -33762,12 +33779,6 @@ "type" : "integer", "format" : "int32" }, - "disabledValues" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, "minLength" : { "type" : "integer", "format" : "int32" @@ -33779,11 +33790,11 @@ "required" : { "type" : "boolean" }, - "eventId" : { + "additionalServiceId" : { "type" : "integer", "format" : "int32" }, - "additionalServiceId" : { + "eventId" : { "type" : "integer", "format" : "int32" }, @@ -33799,6 +33810,12 @@ "editable" : { "type" : "boolean" }, + "disabledValues" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, "inputField" : { "type" : "boolean" }, From b2343cf9c37b0e500e45ef67877671185ea95994 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Wed, 15 Feb 2023 19:02:14 +0100 Subject: [PATCH 156/218] do not include PIN in the email if configuration forbids it --- src/main/java/alfio/manager/TicketReservationManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 2a2c10f92e..498d88b1c9 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -886,10 +886,11 @@ public void sendConfirmationEmail(PurchaseContext purchaseContext, TicketReserva if(purchaseContext.ofType(PurchaseContextType.subscription)) { var firstSubscription = subscriptionRepository.findSubscriptionsByReservationId(reservationId).stream().findFirst().orElseThrow(); boolean sendSeparateEmailToOwner = !Objects.equals(firstSubscription.getEmail(), ticketReservation.getEmail()); + var metadata = Objects.requireNonNullElseGet(subscriptionRepository.getSubscriptionMetadata(firstSubscription.getId()), SubscriptionMetadata::empty); Map initialModel = Map.of( "pin", firstSubscription.getPin(), "subscriptionId", firstSubscription.getId(), - "includePin", true, + "includePin", metadata.getConfiguration().isDisplayPin(), "fullName", firstSubscription.getFirstName() + " " + firstSubscription.getLastName()); var model = prepareModelForReservationEmail(purchaseContext, ticketReservation, vat, summary, List.of(), initialModel); var subscriptionAttachments = new ArrayList<>(attachments); From a00c7248b49a0afda0ab009078ce7c2be2d12fbf Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Sat, 4 Mar 2023 21:17:50 +0100 Subject: [PATCH 157/218] Fix spring-session <-> spring security integration + session removal on user deletion/disable (#1199) spring-session: configure the correct integration with spring-security, allowing us to save the user principal in the db column --- .../java/alfio/config/MvcConfiguration.java | 7 +++++ .../AbstractFormBasedWebSecurity.java | 12 ++++++-- .../authentication/FormBasedWebSecurity.java | 7 +++-- .../OpenIdAdminWebSecurity.java | 7 +++-- .../api/admin/UsersApiController.java | 7 ++--- .../java/alfio/manager/user/UserManager.java | 28 ++++++++++++++++--- src/test/java/alfio/TestConfiguration.java | 7 +++++ 7 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/main/java/alfio/config/MvcConfiguration.java b/src/main/java/alfio/config/MvcConfiguration.java index b07d912d38..4ca3be85cc 100644 --- a/src/main/java/alfio/config/MvcConfiguration.java +++ b/src/main/java/alfio/config/MvcConfiguration.java @@ -28,7 +28,9 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; import org.springframework.session.web.http.CookieHttpSessionIdResolver; import org.springframework.session.web.http.HeaderHttpSessionIdResolver; import org.springframework.session.web.http.HttpSessionIdResolver; @@ -129,6 +131,11 @@ public ViewResolver viewResolver() { return resolver; } + @Bean + public SpringSessionBackedSessionRegistry sessionRegistry(FindByIndexNameSessionRepository sessionRepository) { + return new SpringSessionBackedSessionRegistry<>(sessionRepository); + } + @Bean public HttpSessionIdResolver httpSessionIdResolver() { var publicSessionIdResolver = HeaderHttpSessionIdResolver.xAuthToken(); diff --git a/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java b/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java index 8f2fb7503f..39e7bd12ce 100644 --- a/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java +++ b/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java @@ -45,6 +45,8 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.NegatedRequestMatcher; import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; +import org.springframework.session.FindByIndexNameSessionRepository; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; import javax.servlet.Filter; import javax.servlet.RequestDispatcher; @@ -90,6 +92,7 @@ abstract class AbstractFormBasedWebSecurity { private final DataSource dataSource; private final PasswordEncoder passwordEncoder; private final PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager; + private final SpringSessionBackedSessionRegistry sessionRegistry; protected AbstractFormBasedWebSecurity(Environment environment, UserManager userManager, @@ -98,7 +101,8 @@ protected AbstractFormBasedWebSecurity(Environment environment, CsrfTokenRepository csrfTokenRepository, DataSource dataSource, PasswordEncoder passwordEncoder, - PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager) { + PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager, + SpringSessionBackedSessionRegistry sessionRegistry) { this.environment = environment; this.userManager = userManager; this.recaptchaService = recaptchaService; @@ -107,6 +111,7 @@ protected AbstractFormBasedWebSecurity(Environment environment, this.dataSource = dataSource; this.passwordEncoder = passwordEncoder; this.publicOpenIdAuthenticationManager = publicOpenIdAuthenticationManager; + this.sessionRegistry = sessionRegistry; } @@ -132,7 +137,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .loginProcessingUrl(AUTHENTICATE) .defaultSuccessUrl("/admin") .failureUrl("/authentication?failed") - .and().logout().permitAll(); + .and().logout().permitAll() + .and() + // this allows us to sync between spring session and spring security, thus saving the principal name in the session table + .sessionManagement().maximumSessions(-1).sessionRegistry(sessionRegistry); http.addFilterBefore(openIdPublicCallbackLoginFilter(publicOpenIdAuthenticationManager, authenticationManager), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(openIdPublicAuthenticationFilter(publicOpenIdAuthenticationManager), AnonymousAuthenticationFilter.class); diff --git a/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java b/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java index b9372dd76b..95087317e4 100644 --- a/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java +++ b/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java @@ -26,6 +26,7 @@ import org.springframework.core.env.Environment; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; import javax.sql.DataSource; @@ -43,7 +44,8 @@ public FormBasedWebSecurity(Environment environment, CsrfTokenRepository csrfTokenRepository, DataSource dataSource, PasswordEncoder passwordEncoder, - PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager) { + PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager, + SpringSessionBackedSessionRegistry sessionRegistry) { super(environment, userManager, recaptchaService, @@ -51,6 +53,7 @@ public FormBasedWebSecurity(Environment environment, csrfTokenRepository, dataSource, passwordEncoder, - publicOpenIdAuthenticationManager); + publicOpenIdAuthenticationManager, + sessionRegistry); } } diff --git a/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java b/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java index 000e77e37c..b2bffe46de 100644 --- a/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java +++ b/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java @@ -35,6 +35,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; import javax.sql.DataSource; @@ -55,7 +56,8 @@ public OpenIdAdminWebSecurity(Environment environment, DataSource dataSource, PasswordEncoder passwordEncoder, AdminOpenIdAuthenticationManager adminOpenIdAuthenticationManager, - PublicOpenIdAuthenticationManager openIdAuthenticationManager) { + PublicOpenIdAuthenticationManager openIdAuthenticationManager, + SpringSessionBackedSessionRegistry sessionRegistry) { super(environment, userManager, recaptchaService, @@ -63,7 +65,8 @@ public OpenIdAdminWebSecurity(Environment environment, csrfTokenRepository, dataSource, passwordEncoder, - openIdAuthenticationManager); + openIdAuthenticationManager, + sessionRegistry); this.adminOpenIdAuthenticationManager = adminOpenIdAuthenticationManager; } diff --git a/src/main/java/alfio/controller/api/admin/UsersApiController.java b/src/main/java/alfio/controller/api/admin/UsersApiController.java index 4d210ac98e..0ada6ed254 100644 --- a/src/main/java/alfio/controller/api/admin/UsersApiController.java +++ b/src/main/java/alfio/controller/api/admin/UsersApiController.java @@ -36,7 +36,6 @@ import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.*; @@ -268,7 +267,7 @@ public UserModification loadCurrentUser(Principal principal) { @PostMapping("/users/current/update-password") public ValidationResult updateCurrentUserPassword(@RequestBody PasswordModification passwordModification, Principal principal) { return userManager.validateNewPassword(principal.getName(), passwordModification.oldPassword, passwordModification.newPassword, passwordModification.newPasswordConfirm) - .ifSuccess(() -> userManager.updatePassword(principal.getName(), passwordModification.newPassword)); + .ifSuccess(() -> userManager.updateCurrentUserPassword(principal.getName(), passwordModification.newPassword)); } @PostMapping("/users/current/edit") @@ -279,8 +278,8 @@ public void updateCurrentUser(@RequestBody UserModification userModification, Pr } @PutMapping("/users/{id}/reset-password") - public UserWithPasswordAndQRCode resetPassword(@PathVariable("id") int userId, @RequestParam("baseUrl") String baseUrl) { - UserWithPassword userWithPassword = userManager.resetPassword(userId); + public UserWithPasswordAndQRCode resetPassword(@PathVariable("id") int userId, @RequestParam("baseUrl") String baseUrl, Principal principal) { + UserWithPassword userWithPassword = userManager.resetPassword(userId, principal.getName()); return new UserWithPasswordAndQRCode(userWithPassword, Base64.getEncoder().encodeToString(generateQRCode(userWithPassword, baseUrl))); } diff --git a/src/main/java/alfio/manager/user/UserManager.java b/src/main/java/alfio/manager/user/UserManager.java index fefe63f134..329a4bebfc 100644 --- a/src/main/java/alfio/manager/user/UserManager.java +++ b/src/main/java/alfio/manager/user/UserManager.java @@ -34,6 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -64,18 +65,22 @@ public class UserManager { private final PasswordEncoder passwordEncoder; private final InvoiceSequencesRepository invoiceSequencesRepository; + private final FindByIndexNameSessionRepository sessionsByPrincipalFinder; + public UserManager(AuthorityRepository authorityRepository, OrganizationRepository organizationRepository, UserOrganizationRepository userOrganizationRepository, UserRepository userRepository, PasswordEncoder passwordEncoder, - InvoiceSequencesRepository invoiceSequencesRepository) { + InvoiceSequencesRepository invoiceSequencesRepository, + FindByIndexNameSessionRepository sessionsByPrincipalFinder) { this.authorityRepository = authorityRepository; this.organizationRepository = organizationRepository; this.userOrganizationRepository = userOrganizationRepository; this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.invoiceSequencesRepository = invoiceSequencesRepository; + this.sessionsByPrincipalFinder = sessionsByPrincipalFinder; } private List getUserAuthorities(User user) { @@ -285,15 +290,20 @@ public UserWithPassword insertUser(int organizationId, String username, String f } - public UserWithPassword resetPassword(int userId) { + public UserWithPassword resetPassword(int userId, String currentUser) { User user = findUser(userId); String password = PasswordGenerator.generateRandomPassword(); Validate.isTrue(userRepository.resetPassword(userId, passwordEncoder.encode(password)) == 1, "error during password reset"); + + if (!currentUser.equals(user.getUsername())) { + invalidateSessionsForUser(user.getUsername()); + } + return new UserWithPassword(user, password, UUID.randomUUID().toString()); } - public void updatePassword(String username, String newPassword) { + public void updateCurrentUserPassword(String username, String newPassword) { User user = userRepository.findByUsername(username).orElseThrow(IllegalStateException::new); Validate.isTrue(PasswordGenerator.isValid(newPassword), "invalid password"); Validate.isTrue(userRepository.resetPassword(user.getId(), passwordEncoder.encode(newPassword)) == 1, "error during password update"); @@ -303,14 +313,24 @@ public void updatePassword(String username, String newPassword) { public void deleteUser(int userId, String currentUsername) { User currentUser = userRepository.findEnabledByUsername(currentUsername).orElseThrow(IllegalArgumentException::new); Assert.isTrue(userId != currentUser.getId(), "sorry but you cannot delete your own account."); + var userToDelete = userRepository.findById(userId); userRepository.deleteUserAndReferences(userId); + invalidateSessionsForUser(userToDelete.getUsername()); + } + + private void invalidateSessionsForUser(String username) { + var sessionsToInvalidate = sessionsByPrincipalFinder.findByPrincipalName(username).keySet(); + sessionsToInvalidate.forEach(sessionsByPrincipalFinder::deleteById); } public void enable(int userId, String currentUsername, boolean status) { User currentUser = userRepository.findEnabledByUsername(currentUsername).orElseThrow(IllegalArgumentException::new); Assert.isTrue(userId != currentUser.getId(), "sorry but you cannot commit suicide"); - userRepository.toggleEnabled(userId, status); + if (!status) { // disable user + var userToDisable = userRepository.findById(userId); + invalidateSessionsForUser(userToDisable.getUsername()); + } } public ValidationResult validateUser(Integer id, String username, String firstName, String lastName, String emailAddress) { diff --git a/src/test/java/alfio/TestConfiguration.java b/src/test/java/alfio/TestConfiguration.java index 7da4bfdee3..83b09b3f25 100644 --- a/src/test/java/alfio/TestConfiguration.java +++ b/src/test/java/alfio/TestConfiguration.java @@ -26,12 +26,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.env.Environment; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.session.FindByIndexNameSessionRepository; import java.time.Duration; import java.util.Map; @@ -68,4 +70,9 @@ ObjectMapper objectMapper() { CsrfTokenRepository csrfTokenRepository() { return new CookieCsrfTokenRepository(); } + + @Bean + FindByIndexNameSessionRepository sessionsByPrincipalFinder() { + return Mockito.mock(FindByIndexNameSessionRepository.class); + } } From 94e2923a317452e337393789c9f3192dfc1ddac2 Mon Sep 17 00:00:00 2001 From: Sylvain Jermini Date: Tue, 7 Mar 2023 08:43:58 +0100 Subject: [PATCH 158/218] fix various findings (#1200) (#1201) * fix issue found by @yelprofessor : avoid binding for potentially user controlled input * csv export: escape with a tab if first char is one that would trigger the formula expansion --- src/main/java/alfio/util/ExportUtils.java | 21 ++++++++++++++++++- .../alfio/web-templates/admin-index.ms | 4 ++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/alfio/util/ExportUtils.java b/src/main/java/alfio/util/ExportUtils.java index 2cbd66ffb5..244a0790d5 100644 --- a/src/main/java/alfio/util/ExportUtils.java +++ b/src/main/java/alfio/util/ExportUtils.java @@ -20,6 +20,7 @@ import ch.digitalfondue.basicxlsx.StreamingWorkbook; import ch.digitalfondue.basicxlsx.Style; import com.opencsv.CSVWriter; +import org.apache.commons.lang3.StringUtils; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; @@ -74,6 +75,17 @@ public static void addSheetToWorkbook(String sheetName, } } + // https://owasp.org/www-community/attacks/CSV_Injection + private static String escapeFormulaChar(String s) { + var trimmed = StringUtils.trimToEmpty(s); + // tab and carriage return are removed by the trimming + var res = trimmed; + if (StringUtils.startsWithAny(trimmed, "=", "+", "-", "@")) { + res = "\t" + trimmed; // http://georgemauer.net/2017/10/07/csv-injection.html starting with a tab seems to be enough? + } + return res; + } + public static void exportCsv(String fileName, String[] header, Stream data, HttpServletResponse response) throws IOException { response.setContentType("text/csv;charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=" + fileName); @@ -83,7 +95,14 @@ public static void exportCsv(String fileName, String[] header, Stream out.write(marker); } writer.writeNext(header); - data.forEachOrdered(writer::writeNext); + data.forEachOrdered(d -> { + var copy = Arrays.copyOf(d, d.length); + for (var i = 0; i < copy.length; i++) { + var res = copy[i]; + copy[i] = escapeFormulaChar(res); + } + writer.writeNext(copy); + }); writer.flush(); out.flush(); } diff --git a/src/main/resources/alfio/web-templates/admin-index.ms b/src/main/resources/alfio/web-templates/admin-index.ms index 717f1272ad..26d677d129 100644 --- a/src/main/resources/alfio/web-templates/admin-index.ms +++ b/src/main/resources/alfio/web-templates/admin-index.ms @@ -195,7 +195,7 @@ @@ -203,7 +203,7 @@ {{#eventImage}}{{/eventImage}} {{^eventImage}}{{/eventImage}} - +
{{purchaseContext.displayName}}

{{purchaseContext.displayName}}

{{#i18n}}invoice.vat-invoice [{{vatTranslation}}]{{/i18n}}

+

+ {{#proforma}}{{#i18n}}invoice.proforma [{{vatTranslation}}]{{/i18n}}{{/proforma}} + {{^proforma}}{{#i18n}}invoice.vat-invoice [{{vatTranslation}}]{{/i18n}}{{/proforma}} +

+
@@ -199,27 +220,8 @@ -
-

{{#i18n}}invoice.order-information{{/i18n}}

-

{{ticketReservation.id}}

-

{{#i18n}}invoice.buyer{{/i18n}} {{ticketReservation.fullName}} <{{ticketReservation.email}}>

- {{#hasRefund}} -

{{#i18n}}invoice.refund [{{purchaseContext.currency}} {{orderSummary.refundedAmount}}]{{/i18n}}

- {{/hasRefund}} -
- - {{#invoicingAdditionalInfo}} -
{{#italianEInvoicing}}
-{{#i18n}}invoice.vat [{{vatTranslation}}]{{/i18n}}: {{ticketReservation.vatNr}}
-{{#i18n}}invoice-fields.fiscalCode{{/i18n}}: {{fiscalCode}}
-{{#i18n}}invoice-fields.addresseeItalyEInvoice{{/i18n}}: {{referenceType}}
-{{#i18n}}invoice-fields.addressee-code{{/i18n}}: {{addresseeCode}}
-PEC: {{pec}}{{/italianEInvoicing}}
-        
- {{/invoicingAdditionalInfo}} - {{#isOfflinePayment}} -
+

{{#i18n}}invoice.payment-instruction-no-later-than [{{#format-date}}{{expirationDate}} {{#i18n}}datetime.pattern{{/i18n}} locale:{{#i18n}}locale{{/i18n}}{{/format-date}}]{{/i18n}}


{{#i18n}}invoice.payment-instruction{{/i18n}}

@@ -236,9 +238,46 @@ PEC: {{pec}}{{/italianEInvoicing}}

{{#i18n}}invoice.payment-contact [{{organization.email}}]{{/i18n}}

{{/isOfflinePayment}} +
+

{{#i18n}}invoice.regards{{/i18n}}

+

{{organization.name}}

+
-

{{#i18n}}invoice.regards{{/i18n}}

-

{{organization.name}}

- + \ No newline at end of file From c821aa9edae7b5f86b77d177526c7d5248909e64 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Fri, 14 Apr 2023 19:30:42 +0200 Subject: [PATCH 183/218] fix failing test --- src/test/resources/api/descriptor.json | 4716 ++++++++++++------------ 1 file changed, 2358 insertions(+), 2358 deletions(-) diff --git a/src/test/resources/api/descriptor.json b/src/test/resources/api/descriptor.json index f579197004..f0aae51711 100644 --- a/src/test/resources/api/descriptor.json +++ b/src/test/resources/api/descriptor.json @@ -39,8 +39,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -49,8 +49,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -120,8 +120,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -130,8 +130,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -191,8 +191,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -201,8 +201,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -258,8 +258,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -268,8 +268,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -324,8 +324,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -334,8 +334,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -402,8 +402,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -412,8 +412,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -476,8 +476,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -486,8 +486,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -558,8 +558,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -568,8 +568,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -640,8 +640,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -650,8 +650,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -712,148 +712,6 @@ } } }, - "400" : { - "description" : "Bad Request", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "405" : { - "description" : "Method Not Allowed", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "200" : { - "description" : "OK", - "content" : { - "*/*" : { - "schema" : { - "type" : "boolean" - } - } - } - } - } - } - }, - "/admin/api/users/{id}/reset-password" : { - "put" : { - "tags" : [ "users-api-controller" ], - "operationId" : "resetPassword", - "parameters" : [ { - "name" : "id", - "in" : "path", - "required" : true, - "schema" : { - "type" : "integer", - "format" : "int32" - } - }, { - "name" : "baseUrl", - "in" : "query", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "500" : { - "description" : "Internal Server Error", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "405" : { - "description" : "Method Not Allowed", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "200" : { - "description" : "OK", - "content" : { - "*/*" : { - "schema" : { - "$ref" : "#/components/schemas/UserWithPasswordAndQRCode" - } - } - } - } - } - } - }, - "/admin/api/system/api-key" : { - "get" : { - "tags" : [ "system-api-key-api-controller" ], - "operationId" : "retrieveApiKey", - "responses" : { - "500" : { - "description" : "Internal Server Error", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -864,42 +722,6 @@ } } }, - "401" : { - "description" : "Unauthorized", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "200" : { - "description" : "OK", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - } - } - }, - "put" : { - "tags" : [ "system-api-key-api-controller" ], - "operationId" : "rotateApiKey", - "responses" : { - "500" : { - "description" : "Internal Server Error", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "400" : { "description" : "Bad Request", "content" : { @@ -910,16 +732,194 @@ } } }, - "405" : { - "description" : "Method Not Allowed", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "boolean" + } + } + } + } + } + } + }, + "/admin/api/users/{id}/reset-password" : { + "put" : { + "tags" : [ "users-api-controller" ], + "operationId" : "resetPassword", + "parameters" : [ { + "name" : "id", + "in" : "path", + "required" : true, + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "baseUrl", + "in" : "query", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/UserWithPasswordAndQRCode" + } + } + } + } + } + } + }, + "/admin/api/system/api-key" : { + "get" : { + "tags" : [ "system-api-key-api-controller" ], + "operationId" : "retrieveApiKey", + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + } + } + }, + "put" : { + "tags" : [ "system-api-key-api-controller" ], + "operationId" : "rotateApiKey", + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "401" : { "description" : "Unauthorized", "content" : { @@ -981,8 +981,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -991,8 +991,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1072,8 +1072,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1082,8 +1082,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1153,8 +1153,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1163,8 +1163,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1242,8 +1242,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1252,8 +1252,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1329,8 +1329,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1339,8 +1339,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1403,8 +1403,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1413,8 +1413,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1482,8 +1482,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1492,8 +1492,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1548,8 +1548,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1558,8 +1558,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1622,8 +1622,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1632,8 +1632,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1696,8 +1696,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1706,8 +1706,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1770,8 +1770,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1780,8 +1780,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1852,8 +1852,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1862,8 +1862,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -1934,8 +1934,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -1944,8 +1944,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2002,8 +2002,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2012,8 +2012,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2076,8 +2076,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2086,8 +2086,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2145,8 +2145,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2155,8 +2155,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2222,8 +2222,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2232,8 +2232,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2310,8 +2310,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2320,8 +2320,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2383,8 +2383,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2393,8 +2393,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2458,8 +2458,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2468,8 +2468,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2516,8 +2516,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2526,8 +2526,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2582,8 +2582,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2592,8 +2592,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2655,8 +2655,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2665,8 +2665,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2736,8 +2736,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2746,8 +2746,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2794,8 +2794,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2804,8 +2804,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2860,8 +2860,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2870,8 +2870,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2916,8 +2916,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2926,8 +2926,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -2974,8 +2974,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -2984,8 +2984,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3040,8 +3040,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3050,8 +3050,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3104,16 +3104,6 @@ } } }, - "400" : { - "description" : "Bad Request", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -3124,77 +3114,6 @@ } } }, - "401" : { - "description" : "Unauthorized", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "200" : { - "description" : "OK", - "content" : { - "*/*" : { - "schema" : { - "$ref" : "#/components/schemas/ValidatedResponseString" - } - } - } - } - } - } - }, - "/api/v2/public/reservation/{reservationId}/validate-to-overview" : { - "post" : { - "tags" : [ "reservation-api-v-2-controller" ], - "operationId" : "validateToOverview", - "parameters" : [ { - "name" : "reservationId", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "lang", - "in" : "query", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "ignoreWarnings", - "in" : "query", - "required" : false, - "schema" : { - "type" : "boolean", - "default" : false - } - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ContactAndTicketsForm" - } - } - }, - "required" : true - }, - "responses" : { - "500" : { - "description" : "Internal Server Error", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "400" : { "description" : "Bad Request", "content" : { @@ -3205,16 +3124,6 @@ } } }, - "405" : { - "description" : "Method Not Allowed", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "401" : { "description" : "Unauthorized", "content" : { @@ -3230,7 +3139,7 @@ "content" : { "*/*" : { "schema" : { - "$ref" : "#/components/schemas/ValidatedResponseBoolean" + "$ref" : "#/components/schemas/ValidatedResponseString" } } } @@ -3238,10 +3147,10 @@ } } }, - "/api/v2/public/event/{eventName}/reservation/{reservationId}/validate-to-overview" : { + "/api/v2/public/reservation/{reservationId}/validate-to-overview" : { "post" : { "tags" : [ "reservation-api-v-2-controller" ], - "operationId" : "validateToOverview_1", + "operationId" : "validateToOverview", "parameters" : [ { "name" : "reservationId", "in" : "path", @@ -3286,6 +3195,16 @@ } } }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "400" : { "description" : "Bad Request", "content" : { @@ -3296,6 +3215,77 @@ } } }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/ValidatedResponseBoolean" + } + } + } + } + } + } + }, + "/api/v2/public/event/{eventName}/reservation/{reservationId}/validate-to-overview" : { + "post" : { + "tags" : [ "reservation-api-v-2-controller" ], + "operationId" : "validateToOverview_1", + "parameters" : [ { + "name" : "reservationId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "lang", + "in" : "query", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "ignoreWarnings", + "in" : "query", + "required" : false, + "schema" : { + "type" : "boolean", + "default" : false + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ContactAndTicketsForm" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -3306,6 +3296,16 @@ } } }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "401" : { "description" : "Unauthorized", "content" : { @@ -3366,8 +3366,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3376,8 +3376,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3446,8 +3446,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3456,8 +3456,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3512,8 +3512,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3522,8 +3522,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3578,8 +3578,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3588,8 +3588,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3654,8 +3654,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3664,8 +3664,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3720,8 +3720,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3730,8 +3730,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3801,8 +3801,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3811,8 +3811,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3865,8 +3865,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3875,8 +3875,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -3931,8 +3931,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -3941,8 +3941,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4012,8 +4012,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4022,8 +4022,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4076,8 +4076,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4086,8 +4086,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4152,8 +4152,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4162,8 +4162,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4225,8 +4225,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4235,8 +4235,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4308,8 +4308,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4318,8 +4318,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4392,8 +4392,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4402,8 +4402,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4468,8 +4468,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4478,8 +4478,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4535,8 +4535,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4545,8 +4545,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4610,8 +4610,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4620,8 +4620,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4675,8 +4675,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4685,8 +4685,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4736,8 +4736,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4746,8 +4746,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4813,8 +4813,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4823,8 +4823,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4880,8 +4880,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4890,8 +4890,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -4961,8 +4961,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -4971,8 +4971,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5040,8 +5040,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5050,8 +5050,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5108,8 +5108,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5118,8 +5118,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5184,8 +5184,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5194,8 +5194,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5250,8 +5250,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5260,8 +5260,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5326,8 +5326,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5336,8 +5336,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5394,8 +5394,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5404,8 +5404,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5633,8 +5633,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5643,8 +5643,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5712,8 +5712,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5722,8 +5722,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5781,8 +5781,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5791,8 +5791,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5858,8 +5858,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5868,8 +5868,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -5943,8 +5943,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -5953,8 +5953,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6009,8 +6009,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -6019,8 +6019,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6083,8 +6083,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -6093,8 +6093,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6159,8 +6159,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -6169,8 +6169,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6227,8 +6227,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -6237,8 +6237,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6295,8 +6295,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -6305,8 +6305,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6363,8 +6363,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -6373,8 +6373,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6424,8 +6424,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -6434,8 +6434,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -6773,16 +6773,6 @@ } } }, - "400" : { - "description" : "Bad Request", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -6793,75 +6783,6 @@ } } }, - "401" : { - "description" : "Unauthorized", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "200" : { - "description" : "OK", - "content" : { - "*/*" : { - "schema" : { - "$ref" : "#/components/schemas/ResultTicketReservationDescriptor" - } - } - } - } - } - }, - "post" : { - "tags" : [ "admin-reservation-api-controller" ], - "operationId" : "updateReservation", - "parameters" : [ { - "name" : "purchaseContextType", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string", - "enum" : [ "subscription", "event" ] - } - }, { - "name" : "publicIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "reservationId", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/AdminReservationModification" - } - } - }, - "required" : true - }, - "responses" : { - "500" : { - "description" : "Internal Server Error", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "400" : { "description" : "Bad Request", "content" : { @@ -6872,16 +6793,6 @@ } } }, - "405" : { - "description" : "Method Not Allowed", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "401" : { "description" : "Unauthorized", "content" : { @@ -6897,18 +6808,16 @@ "content" : { "*/*" : { "schema" : { - "$ref" : "#/components/schemas/ResultBoolean" + "$ref" : "#/components/schemas/ResultTicketReservationDescriptor" } } } } } - } - }, - "/admin/api/reservation/{purchaseContextType}/{publicIdentifier}/{reservationId}/refund" : { + }, "post" : { "tags" : [ "admin-reservation-api-controller" ], - "operationId" : "refund", + "operationId" : "updateReservation", "parameters" : [ { "name" : "purchaseContextType", "in" : "path", @@ -6936,7 +6845,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RefundAmount" + "$ref" : "#/components/schemas/AdminReservationModification" } } }, @@ -6953,6 +6862,16 @@ } } }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "400" : { "description" : "Bad Request", "content" : { @@ -6963,6 +6882,77 @@ } } }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/ResultBoolean" + } + } + } + } + } + } + }, + "/admin/api/reservation/{purchaseContextType}/{publicIdentifier}/{reservationId}/refund" : { + "post" : { + "tags" : [ "admin-reservation-api-controller" ], + "operationId" : "refund", + "parameters" : [ { + "name" : "purchaseContextType", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string", + "enum" : [ "subscription", "event" ] + } + }, { + "name" : "publicIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "reservationId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/RefundAmount" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -6973,6 +6963,16 @@ } } }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "401" : { "description" : "Unauthorized", "content" : { @@ -7049,8 +7049,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7059,8 +7059,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7153,8 +7153,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7163,8 +7163,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7237,8 +7237,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7247,8 +7247,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7320,8 +7320,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7330,8 +7330,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7388,8 +7388,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7398,8 +7398,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7458,8 +7458,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7468,8 +7468,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7516,8 +7516,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7526,8 +7526,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7576,8 +7576,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7586,8 +7586,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7738,8 +7738,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7748,8 +7748,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7806,8 +7806,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7816,8 +7816,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7874,8 +7874,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7884,8 +7884,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -7942,8 +7942,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -7952,8 +7952,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8017,8 +8017,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8027,8 +8027,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8100,8 +8100,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8110,8 +8110,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8174,8 +8174,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8184,8 +8184,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8244,8 +8244,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8254,8 +8254,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8553,8 +8553,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8563,8 +8563,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8611,8 +8611,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8621,8 +8621,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8680,8 +8680,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8690,8 +8690,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8753,8 +8753,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8763,8 +8763,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8834,8 +8834,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8844,8 +8844,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8905,8 +8905,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8915,8 +8915,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -8978,8 +8978,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -8988,8 +8988,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9042,8 +9042,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9052,8 +9052,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9122,8 +9122,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9132,8 +9132,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9195,8 +9195,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9205,8 +9205,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9265,8 +9265,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9275,8 +9275,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9342,8 +9342,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9352,8 +9352,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9415,8 +9415,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9425,8 +9425,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9491,8 +9491,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9501,8 +9501,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9751,8 +9751,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9761,8 +9761,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9835,8 +9835,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9845,8 +9845,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -9925,8 +9925,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -9935,8 +9935,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10009,8 +10009,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10019,8 +10019,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10074,8 +10074,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10084,8 +10084,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10149,8 +10149,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10159,8 +10159,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10224,8 +10224,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10234,8 +10234,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10293,8 +10293,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10303,8 +10303,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10364,8 +10364,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10374,8 +10374,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10442,8 +10442,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10452,8 +10452,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10519,8 +10519,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10529,8 +10529,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10587,8 +10587,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10597,8 +10597,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10655,8 +10655,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10665,8 +10665,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10739,8 +10739,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10749,8 +10749,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -10806,16 +10806,6 @@ } } }, - "400" : { - "description" : "Bad Request", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -10826,64 +10816,6 @@ } } }, - "401" : { - "description" : "Unauthorized", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "200" : { - "description" : "OK", - "content" : { - "*/*" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/AdditionalService" - } - } - } - } - } - } - }, - "post" : { - "tags" : [ "additional-service-api-controller" ], - "operationId" : "insert", - "parameters" : [ { - "name" : "eventId", - "in" : "path", - "required" : true, - "schema" : { - "type" : "integer", - "format" : "int32" - } - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/AdditionalService" - } - } - }, - "required" : true - }, - "responses" : { - "500" : { - "description" : "Internal Server Error", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "400" : { "description" : "Bad Request", "content" : { @@ -10894,16 +10826,84 @@ } } }, - "405" : { - "description" : "Method Not Allowed", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AdditionalService" + } + } + } + } + } + } + }, + "post" : { + "tags" : [ "additional-service-api-controller" ], + "operationId" : "insert", + "parameters" : [ { + "name" : "eventId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/AdditionalService" + } + } + }, + "required" : true + }, + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "401" : { "description" : "Unauthorized", "content" : { @@ -10952,8 +10952,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -10962,8 +10962,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11026,8 +11026,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11036,8 +11036,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11109,8 +11109,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11119,8 +11119,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11200,8 +11200,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11210,8 +11210,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11291,8 +11291,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11301,8 +11301,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11372,8 +11372,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11382,8 +11382,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11462,8 +11462,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11472,8 +11472,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11546,8 +11546,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11556,8 +11556,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11630,8 +11630,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11640,8 +11640,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11712,8 +11712,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11722,8 +11722,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11786,8 +11786,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11796,8 +11796,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11860,8 +11860,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11870,8 +11870,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -11934,8 +11934,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -11944,8 +11944,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12014,8 +12014,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12024,8 +12024,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12102,8 +12102,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12112,8 +12112,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12175,8 +12175,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12185,8 +12185,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12248,8 +12248,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12258,8 +12258,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12338,8 +12338,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12348,8 +12348,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12432,8 +12432,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12442,8 +12442,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12503,8 +12503,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12513,8 +12513,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12571,8 +12571,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12581,8 +12581,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12653,8 +12653,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12663,8 +12663,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12711,8 +12711,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12721,8 +12721,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12772,8 +12772,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12782,8 +12782,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12838,8 +12838,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12848,8 +12848,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -12959,8 +12959,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -12969,8 +12969,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13025,8 +13025,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13035,8 +13035,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13098,8 +13098,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13108,8 +13108,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13171,8 +13171,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13181,8 +13181,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13229,8 +13229,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13239,8 +13239,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13298,8 +13298,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13308,8 +13308,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13367,8 +13367,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13377,8 +13377,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13436,8 +13436,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13446,8 +13446,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13513,8 +13513,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13523,8 +13523,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13582,8 +13582,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13592,8 +13592,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13651,8 +13651,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13661,8 +13661,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13724,8 +13724,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13734,8 +13734,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13797,8 +13797,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13807,8 +13807,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13870,8 +13870,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13880,8 +13880,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -13950,8 +13950,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -13960,8 +13960,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14023,8 +14023,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14033,8 +14033,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14089,8 +14089,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14099,8 +14099,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14155,8 +14155,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14165,8 +14165,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14228,8 +14228,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14238,8 +14238,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14294,8 +14294,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14304,8 +14304,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14360,8 +14360,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14370,8 +14370,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14441,8 +14441,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14451,8 +14451,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14514,8 +14514,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14524,8 +14524,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14594,8 +14594,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14604,8 +14604,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14645,8 +14645,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14655,8 +14655,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14719,8 +14719,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14729,8 +14729,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14780,8 +14780,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14790,8 +14790,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14850,8 +14850,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14860,8 +14860,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14916,8 +14916,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14926,8 +14926,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -14982,8 +14982,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -14992,8 +14992,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15201,8 +15201,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15211,8 +15211,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15274,8 +15274,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15284,8 +15284,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15359,8 +15359,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15369,8 +15369,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15448,8 +15448,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15458,8 +15458,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15522,8 +15522,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15532,8 +15532,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15603,8 +15603,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15613,8 +15613,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15680,8 +15680,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15690,8 +15690,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15765,8 +15765,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15775,8 +15775,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15834,8 +15834,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15844,8 +15844,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15900,8 +15900,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15910,8 +15910,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -15958,8 +15958,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -15968,8 +15968,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16019,8 +16019,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16029,8 +16029,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16080,8 +16080,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16090,8 +16090,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16141,8 +16141,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16151,8 +16151,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16211,8 +16211,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16221,8 +16221,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16276,8 +16276,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16286,8 +16286,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16334,8 +16334,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16344,8 +16344,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16392,8 +16392,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16402,8 +16402,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16453,8 +16453,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16463,8 +16463,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -16511,8 +16511,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -16521,8 +16521,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -17361,8 +17361,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -17371,8 +17371,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -17454,8 +17454,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -17464,8 +17464,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -17542,8 +17542,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -17552,8 +17552,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -17623,16 +17623,6 @@ } } }, - "400" : { - "description" : "Bad Request", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -17643,67 +17633,6 @@ } } }, - "401" : { - "description" : "Unauthorized", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, - "200" : { - "description" : "OK", - "content" : { - "*/*" : { - "schema" : { - "$ref" : "#/components/schemas/ResultTransactionAndPaymentInfo" - } - } - } - } - } - } - }, - "/admin/api/reservation/{purchaseContextType}/{publicIdentifier}/{reservationId}/email-list" : { - "get" : { - "tags" : [ "admin-reservation-api-controller" ], - "operationId" : "getEmailList", - "parameters" : [ { - "name" : "purchaseContextType", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string", - "enum" : [ "subscription", "event" ] - } - }, { - "name" : "publicIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "reservationId", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "500" : { - "description" : "Internal Server Error", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "400" : { "description" : "Bad Request", "content" : { @@ -17714,16 +17643,6 @@ } } }, - "405" : { - "description" : "Method Not Allowed", - "content" : { - "*/*" : { - "schema" : { - "type" : "string" - } - } - } - }, "401" : { "description" : "Unauthorized", "content" : { @@ -17739,7 +17658,7 @@ "content" : { "*/*" : { "schema" : { - "$ref" : "#/components/schemas/ResultListLightweightMailMessage" + "$ref" : "#/components/schemas/ResultTransactionAndPaymentInfo" } } } @@ -17747,10 +17666,10 @@ } } }, - "/admin/api/reservation/{purchaseContextType}/{publicIdentifier}/{reservationId}/billing-documents" : { + "/admin/api/reservation/{purchaseContextType}/{publicIdentifier}/{reservationId}/email-list" : { "get" : { "tags" : [ "admin-reservation-api-controller" ], - "operationId" : "getBillingDocuments", + "operationId" : "getEmailList", "parameters" : [ { "name" : "purchaseContextType", "in" : "path", @@ -17785,6 +17704,16 @@ } } }, + "405" : { + "description" : "Method Not Allowed", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "400" : { "description" : "Bad Request", "content" : { @@ -17795,6 +17724,67 @@ } } }, + "401" : { + "description" : "Unauthorized", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/ResultListLightweightMailMessage" + } + } + } + } + } + } + }, + "/admin/api/reservation/{purchaseContextType}/{publicIdentifier}/{reservationId}/billing-documents" : { + "get" : { + "tags" : [ "admin-reservation-api-controller" ], + "operationId" : "getBillingDocuments", + "parameters" : [ { + "name" : "purchaseContextType", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string", + "enum" : [ "subscription", "event" ] + } + }, { + "name" : "publicIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "reservationId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "500" : { + "description" : "Internal Server Error", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "405" : { "description" : "Method Not Allowed", "content" : { @@ -17805,6 +17795,16 @@ } } }, + "400" : { + "description" : "Bad Request", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + }, "401" : { "description" : "Unauthorized", "content" : { @@ -17874,8 +17874,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -17884,8 +17884,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -17954,8 +17954,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -17964,8 +17964,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18035,8 +18035,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18045,8 +18045,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18135,8 +18135,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18145,8 +18145,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18209,8 +18209,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18219,8 +18219,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18287,8 +18287,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18297,8 +18297,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18357,8 +18357,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18367,8 +18367,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18425,8 +18425,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18435,8 +18435,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18615,8 +18615,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18625,8 +18625,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18685,8 +18685,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18695,8 +18695,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18760,8 +18760,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18770,8 +18770,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18830,8 +18830,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18840,8 +18840,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18900,8 +18900,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18910,8 +18910,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -18970,8 +18970,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -18980,8 +18980,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19031,8 +19031,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19041,8 +19041,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19109,8 +19109,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19119,8 +19119,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19182,8 +19182,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19192,8 +19192,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19240,8 +19240,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19250,8 +19250,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19660,8 +19660,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19670,8 +19670,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19733,8 +19733,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19743,8 +19743,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19813,8 +19813,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19823,8 +19823,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19877,8 +19877,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19887,8 +19887,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -19967,8 +19967,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -19977,8 +19977,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20040,8 +20040,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20050,8 +20050,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20091,8 +20091,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20101,8 +20101,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20167,8 +20167,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20177,8 +20177,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20243,8 +20243,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20253,8 +20253,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20323,8 +20323,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20333,8 +20333,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20397,8 +20397,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20407,8 +20407,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20456,8 +20456,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20466,8 +20466,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20525,8 +20525,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20535,8 +20535,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20592,8 +20592,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20602,8 +20602,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20661,8 +20661,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20671,8 +20671,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20728,8 +20728,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20738,8 +20738,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20805,8 +20805,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20815,8 +20815,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20887,8 +20887,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20897,8 +20897,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -20961,8 +20961,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -20971,8 +20971,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21030,8 +21030,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21040,8 +21040,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21089,8 +21089,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21099,8 +21099,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21156,8 +21156,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21166,8 +21166,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21215,8 +21215,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21225,8 +21225,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21292,8 +21292,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21302,8 +21302,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21362,8 +21362,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21372,8 +21372,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21432,8 +21432,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21442,8 +21442,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21505,8 +21505,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21515,8 +21515,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21575,8 +21575,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21585,8 +21585,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21633,8 +21633,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21643,8 +21643,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21694,8 +21694,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21704,8 +21704,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21753,8 +21753,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21763,8 +21763,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21822,8 +21822,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21832,8 +21832,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21899,8 +21899,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21909,8 +21909,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -21958,8 +21958,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -21968,8 +21968,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22032,8 +22032,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22042,8 +22042,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22099,8 +22099,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22109,8 +22109,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22164,8 +22164,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22174,8 +22174,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22225,8 +22225,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22235,8 +22235,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22296,8 +22296,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22306,8 +22306,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22373,8 +22373,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22383,8 +22383,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22440,8 +22440,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22450,8 +22450,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22504,8 +22504,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22514,8 +22514,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22568,8 +22568,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22578,8 +22578,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22641,8 +22641,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22651,8 +22651,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22708,8 +22708,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22718,8 +22718,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22789,8 +22789,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22799,8 +22799,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22878,8 +22878,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22888,8 +22888,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -22949,8 +22949,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -22959,8 +22959,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23008,8 +23008,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23018,8 +23018,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23069,8 +23069,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23079,8 +23079,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23143,8 +23143,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23153,8 +23153,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23213,8 +23213,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23223,8 +23223,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23288,8 +23288,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23298,8 +23298,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23374,8 +23374,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23384,8 +23384,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23440,8 +23440,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23450,8 +23450,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23507,8 +23507,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23517,8 +23517,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23558,8 +23558,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23568,8 +23568,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23635,8 +23635,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23645,8 +23645,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23708,8 +23708,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23718,8 +23718,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23781,8 +23781,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23791,8 +23791,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23847,8 +23847,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23857,8 +23857,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23913,8 +23913,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23923,8 +23923,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -23980,8 +23980,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -23990,8 +23990,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24039,8 +24039,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24049,8 +24049,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24121,8 +24121,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24131,8 +24131,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24421,8 +24421,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24431,8 +24431,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24489,8 +24489,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24499,8 +24499,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24564,8 +24564,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24574,8 +24574,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24638,8 +24638,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24648,8 +24648,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24727,8 +24727,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24737,8 +24737,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24801,8 +24801,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24811,8 +24811,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24883,8 +24883,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24893,8 +24893,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -24950,8 +24950,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -24960,8 +24960,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -25017,8 +25017,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -25027,8 +25027,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -25081,7 +25081,7 @@ "required" : true, "schema" : { "type" : "string", - "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] + "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ITALY_E_INVOICING_SEND_PROFORMA", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] } } ], "responses" : { @@ -25095,8 +25095,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -25105,8 +25105,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -25161,8 +25161,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -25171,8 +25171,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -25222,7 +25222,7 @@ "required" : true, "schema" : { "type" : "string", - "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] + "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ITALY_E_INVOICING_SEND_PROFORMA", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] } } ], "responses" : { @@ -25236,8 +25236,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -25246,8 +25246,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -25305,7 +25305,7 @@ "required" : true, "schema" : { "type" : "string", - "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] + "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ITALY_E_INVOICING_SEND_PROFORMA", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] } } ], "responses" : { @@ -25319,8 +25319,8 @@ } } }, - "400" : { - "description" : "Bad Request", + "405" : { + "description" : "Method Not Allowed", "content" : { "*/*" : { "schema" : { @@ -25329,8 +25329,8 @@ } } }, - "405" : { - "description" : "Method Not Allowed", + "400" : { + "description" : "Bad Request", "content" : { "*/*" : { "schema" : { @@ -25417,24 +25417,24 @@ "value" : { "type" : "boolean" }, - "warnings" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/WarningMessage" - } - }, - "success" : { - "type" : "boolean" - }, "errorCount" : { "type" : "integer", "format" : "int32" }, + "success" : { + "type" : "boolean" + }, "validationErrors" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ErrorDescriptor" } + }, + "warnings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/WarningMessage" + } } } }, @@ -25571,10 +25571,11 @@ "enabled" : { "type" : "boolean" }, - "description" : { - "type" : "string" + "validTo" : { + "type" : "string", + "format" : "date-time" }, - "username" : { + "description" : { "type" : "string" }, "firstName" : { @@ -25586,13 +25587,12 @@ "emailAddress" : { "type" : "string" }, + "username" : { + "type" : "string" + }, "validToEpochSecond" : { "type" : "integer", "format" : "int64" - }, - "validTo" : { - "type" : "string", - "format" : "date-time" } } }, @@ -25602,15 +25602,15 @@ "location" : { "type" : "string" }, + "description" : { + "type" : "string" + }, "arguments" : { "type" : "array", "items" : { "type" : "object" } }, - "description" : { - "type" : "string" - }, "code" : { "type" : "string" } @@ -25635,11 +25635,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -26001,37 +26001,37 @@ "refundedAmount" : { "type" : "string" }, - "singleTicketOrder" : { + "vatExempt" : { "type" : "boolean" }, - "displayVat" : { - "type" : "boolean" + "priceInCents" : { + "type" : "integer", + "format" : "int32" }, - "totalNetPrice" : { - "type" : "string" + "ticketAmount" : { + "type" : "integer", + "format" : "int32" }, "descriptionForPayment" : { "type" : "string" }, - "displaySplitPaymentNote" : { + "notYetPaid" : { "type" : "boolean" }, - "priceBeforeTaxes" : { - "type" : "string" - }, - "ticketAmount" : { - "type" : "integer", - "format" : "int32" + "singleTicketOrder" : { + "type" : "boolean" }, - "notYetPaid" : { + "displayVat" : { "type" : "boolean" }, - "vatExempt" : { + "totalNetPrice" : { + "type" : "string" + }, + "displaySplitPaymentNote" : { "type" : "boolean" }, - "priceInCents" : { - "type" : "integer", - "format" : "int32" + "priceBeforeTaxes" : { + "type" : "string" } } }, @@ -26098,10 +26098,10 @@ "currencyCode" : { "type" : "string" }, - "dynamic" : { + "fixedAmount" : { "type" : "boolean" }, - "fixedAmount" : { + "dynamic" : { "type" : "boolean" } } @@ -26125,11 +26125,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -26145,14 +26145,14 @@ "key" : { "$ref" : "#/components/schemas/TicketCategory" }, - "left" : { - "$ref" : "#/components/schemas/TicketCategory" - }, "right" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/Ticket" } + }, + "left" : { + "$ref" : "#/components/schemas/TicketCategory" } } }, @@ -26225,13 +26225,13 @@ "valid" : { "type" : "boolean" }, - "formattedValidityTo" : { + "pin" : { "type" : "string" }, - "formattedValidityFrom" : { + "formattedValidityTo" : { "type" : "string" }, - "pin" : { + "formattedValidityFrom" : { "type" : "string" } } @@ -26290,14 +26290,14 @@ "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, + "descriptionForPayment" : { + "type" : "string" + }, "discount" : { "type" : "boolean" }, "taxDetail" : { "type" : "boolean" - }, - "descriptionForPayment" : { - "type" : "string" } } }, @@ -26384,16 +26384,16 @@ "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "formattedNetPrice" : { - "type" : "string" - }, "assigned" : { "type" : "boolean" }, + "formattedFinalPrice" : { + "type" : "string" + }, "checkedIn" : { "type" : "boolean" }, - "formattedFinalPrice" : { + "formattedNetPrice" : { "type" : "string" } } @@ -26592,43 +26592,43 @@ "cancelled" : { "type" : "boolean" }, + "hasInvoiceNumber" : { + "type" : "boolean" + }, "stuck" : { "type" : "boolean" }, "hasBillingAddress" : { "type" : "boolean" }, - "hasVatNumber" : { + "hasInvoiceOrReceiptDocument" : { "type" : "boolean" }, - "hasInvoiceNumber" : { + "hasBeenPaid" : { "type" : "boolean" }, - "pendingOfflinePayment" : { + "hasVatNumber" : { "type" : "boolean" }, - "paidAmount" : { - "type" : "string" - }, "lineSplittedBillingAddress" : { "type" : "array", "items" : { "type" : "string" } }, - "hasInvoiceOrReceiptDocument" : { - "type" : "boolean" + "paidAmount" : { + "type" : "string" }, - "hasBeenPaid" : { + "pendingOfflinePayment" : { "type" : "boolean" }, - "finalPrice" : { + "taxablePrice" : { "type" : "number" }, - "netPrice" : { + "finalPrice" : { "type" : "number" }, - "taxablePrice" : { + "netPrice" : { "type" : "number" } } @@ -26725,76 +26725,30 @@ "type" : "string", "enum" : [ "PENDING", "IN_PAYMENT", "EXTERNAL_PROCESSING_PAYMENT", "WAITING_EXTERNAL_CONFIRMATION", "OFFLINE_PAYMENT", "DEFERRED_OFFLINE_PAYMENT", "FINALIZING", "OFFLINE_FINALIZING", "COMPLETE", "STUCK", "CANCELLED", "CREDIT_NOTE_ISSUED" ] }, - "stuck" : { - "type" : "boolean" - }, - "reminderSent" : { - "type" : "boolean" - }, - "hasBillingAddress" : { - "type" : "boolean" - }, - "hasVatNumber" : { - "type" : "boolean" - }, - "latestReminder" : { - "type" : "string", - "format" : "date-time" - }, - "invoiceModel" : { - "type" : "string" - }, - "usedVatPercent" : { - "type" : "number" - }, - "creationTimestamp" : { - "type" : "string", - "format" : "date-time" - }, - "promoCodeDiscountId" : { - "type" : "integer", - "format" : "int32" - }, - "email" : { - "type" : "string" - }, - "userLanguage" : { - "type" : "string" - }, "firstName" : { "type" : "string" }, "lastName" : { "type" : "string" }, - "hasInvoiceNumber" : { - "type" : "boolean" + "email" : { + "type" : "string" }, "invoiceNumber" : { "type" : "string" }, - "paymentMethod" : { - "type" : "string", - "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] - }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "srcPriceCts" : { + "invoiceRequested" : { + "type" : "boolean" + }, + "finalPriceCts" : { "type" : "integer", "format" : "int32" }, - "finalPrice" : { - "type" : "number" - }, - "vat" : { - "type" : "number" - }, - "appliedDiscount" : { - "type" : "number" - }, - "finalPriceCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, @@ -26806,58 +26760,95 @@ "type" : "integer", "format" : "int32" }, - "vatNr" : { - "type" : "string" + "paymentMethod" : { + "type" : "string", + "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] }, - "vatCountryCode" : { + "vatNr" : { "type" : "string" }, - "invoiceRequested" : { - "type" : "boolean" - }, - "vatPercentageOrZero" : { + "taxablePrice" : { "type" : "number" }, - "netPrice" : { + "appliedDiscount" : { "type" : "number" }, - "pendingOfflinePayment" : { - "type" : "boolean" + "userLanguage" : { + "type" : "string" }, "validity" : { "type" : "string", "format" : "date-time" }, + "promoCodeDiscountId" : { + "type" : "integer", + "format" : "int32" + }, + "confirmationTimestamp" : { + "type" : "string", + "format" : "date-time" + }, + "invoiceModel" : { + "type" : "string" + }, "billingAddress" : { "type" : "string" }, - "customerReference" : { + "latestReminder" : { + "type" : "string", + "format" : "date-time" + }, + "reminderSent" : { + "type" : "boolean" + }, + "directAssignmentRequested" : { + "type" : "boolean" + }, + "vatCountryCode" : { "type" : "string" }, - "registrationTimestamp" : { + "usedVatPercent" : { + "type" : "number" + }, + "vatIncluded" : { + "type" : "boolean" + }, + "creationTimestamp" : { "type" : "string", "format" : "date-time" }, - "confirmationTimestamp" : { + "customerReference" : { + "type" : "string" + }, + "registrationTimestamp" : { "type" : "string", "format" : "date-time" }, + "finalPrice" : { + "type" : "number" + }, + "vat" : { + "type" : "number" + }, "discount" : { "$ref" : "#/components/schemas/PromoCodeDiscount" }, - "paidAmount" : { - "type" : "string" + "netPrice" : { + "type" : "number" }, - "lineSplittedBillingAddress" : { - "type" : "array", - "items" : { - "type" : "string" - } + "vatPercentageOrZero" : { + "type" : "number" }, - "directAssignmentRequested" : { + "optionalVatPercentage" : { + "type" : "number" + }, + "hasInvoiceNumber" : { "type" : "boolean" }, - "vatIncluded" : { + "stuck" : { + "type" : "boolean" + }, + "hasBillingAddress" : { "type" : "boolean" }, "hasInvoiceOrReceiptDocument" : { @@ -26866,11 +26857,20 @@ "hasBeenPaid" : { "type" : "boolean" }, - "optionalVatPercentage" : { - "type" : "number" + "hasVatNumber" : { + "type" : "boolean" }, - "taxablePrice" : { - "type" : "number" + "lineSplittedBillingAddress" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "paidAmount" : { + "type" : "string" + }, + "pendingOfflinePayment" : { + "type" : "boolean" } } }, @@ -27373,24 +27373,24 @@ "value" : { "$ref" : "#/components/schemas/User" }, - "warnings" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/WarningMessage" - } - }, - "success" : { - "type" : "boolean" - }, "errorCount" : { "type" : "integer", "format" : "int32" }, + "success" : { + "type" : "boolean" + }, "validationErrors" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ErrorDescriptor" } + }, + "warnings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/WarningMessage" + } } } }, @@ -27411,24 +27411,24 @@ "value" : { "type" : "string" }, - "warnings" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/WarningMessage" - } - }, - "success" : { - "type" : "boolean" - }, "errorCount" : { "type" : "integer", "format" : "int32" }, + "success" : { + "type" : "boolean" + }, "validationErrors" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ErrorDescriptor" } + }, + "warnings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/WarningMessage" + } } } }, @@ -27562,12 +27562,12 @@ "type" : "string", "enum" : [ "CREDIT_CARD", "PAYPAL", "IDEAL", "BANK_TRANSFER", "ON_SITE", "NONE", "APPLE_PAY", "BANCONTACT", "ING_HOME_PAY", "BELFIUS", "KBC", "PRZELEWY_24", "ALIPAY", "POSTFINANCE", "TWINT" ] }, + "token" : { + "type" : "string" + }, "paymentProvider" : { "type" : "string", "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] - }, - "token" : { - "type" : "string" } } }, @@ -27648,24 +27648,24 @@ "value" : { "$ref" : "#/components/schemas/ReservationPaymentResult" }, - "warnings" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/WarningMessage" - } - }, - "success" : { - "type" : "boolean" - }, "errorCount" : { "type" : "integer", "format" : "int32" }, + "success" : { + "type" : "boolean" + }, "validationErrors" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ErrorDescriptor" } + }, + "warnings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/WarningMessage" + } } } }, @@ -27812,16 +27812,16 @@ "captcha" : { "type" : "string" }, - "additionalServices" : { + "tickets" : { "type" : "array", "items" : { - "$ref" : "#/components/schemas/AdditionalServiceReservationModification" + "$ref" : "#/components/schemas/TicketReservationModification" } }, - "tickets" : { + "additionalServices" : { "type" : "array", "items" : { - "$ref" : "#/components/schemas/TicketReservationModification" + "$ref" : "#/components/schemas/AdditionalServiceReservationModification" } } } @@ -28053,14 +28053,6 @@ "type" : "integer", "format" : "int32" }, - "validityFrom" : { - "type" : "string", - "format" : "date-time" - }, - "validityTo" : { - "type" : "string", - "format" : "date-time" - }, "timeUnit" : { "type" : "string", "enum" : [ "DAYS", "MONTHS", "YEARS" ] @@ -28068,6 +28060,14 @@ "numEntries" : { "type" : "integer", "format" : "int32" + }, + "validityFrom" : { + "type" : "string", + "format" : "date-time" + }, + "validityTo" : { + "type" : "string", + "format" : "date-time" } } }, @@ -28610,50 +28610,33 @@ "currencyCode" : { "type" : "string" }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "assigned" : { - "type" : "boolean" - }, - "email" : { + "firstName" : { "type" : "string" }, - "userLanguage" : { + "lastName" : { "type" : "string" }, - "eventId" : { - "type" : "integer", - "format" : "int32" - }, - "firstName" : { + "email" : { "type" : "string" }, - "lastName" : { - "type" : "string" + "assigned" : { + "type" : "boolean" }, - "subscriptionId" : { - "type" : "string", - "format" : "uuid" + "formattedFinalPrice" : { + "type" : "string" }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "srcPriceCts" : { + "uuid" : { + "type" : "string" + }, + "categoryId" : { "type" : "integer", "format" : "int32" }, @@ -28661,37 +28644,54 @@ "type" : "integer", "format" : "int32" }, - "vatCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "discountCts" : { + "vatCts" : { "type" : "integer", "format" : "int32" }, - "categoryId" : { + "discountCts" : { "type" : "integer", "format" : "int32" }, "ticketsReservationId" : { "type" : "string" }, - "uuid" : { + "eventId" : { + "type" : "integer", + "format" : "int32" + }, + "userLanguage" : { "type" : "string" }, + "tags" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, "lockedAssignment" : { "type" : "boolean" }, "checkedIn" : { "type" : "boolean" }, + "formattedNetPrice" : { + "type" : "string" + }, "creation" : { "type" : "string", "format" : "date-time" }, - "formattedFinalPrice" : { + "extReference" : { "type" : "string" }, + "subscriptionId" : { + "type" : "string", + "format" : "uuid" + }, "categoryName" : { "type" : "string" } @@ -28857,11 +28857,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -28919,11 +28919,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -29258,6 +29258,13 @@ "supportsTicketsGeneration" : { "type" : "boolean" }, + "publicIdentifier" : { + "type" : "string" + }, + "priceCts" : { + "type" : "integer", + "format" : "int32" + }, "validityFromModel" : { "$ref" : "#/components/schemas/DateTimeModification" }, @@ -29269,13 +29276,6 @@ }, "onSaleToModel" : { "$ref" : "#/components/schemas/DateTimeModification" - }, - "publicIdentifier" : { - "type" : "string" - }, - "priceCts" : { - "type" : "integer", - "format" : "int32" } } }, @@ -29378,11 +29378,11 @@ "key" : { "type" : "boolean" }, - "left" : { - "type" : "boolean" - }, "right" : { "type" : "string" + }, + "left" : { + "type" : "boolean" } } }, @@ -29712,12 +29712,12 @@ "TripleBooleanStringString" : { "type" : "object", "properties" : { - "left" : { - "type" : "boolean" - }, "right" : { "type" : "string" }, + "left" : { + "type" : "boolean" + }, "middle" : { "type" : "string" } @@ -29936,50 +29936,33 @@ "currencyCode" : { "type" : "string" }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "assigned" : { - "type" : "boolean" - }, - "email" : { + "firstName" : { "type" : "string" }, - "userLanguage" : { + "lastName" : { "type" : "string" }, - "eventId" : { - "type" : "integer", - "format" : "int32" - }, - "firstName" : { + "email" : { "type" : "string" }, - "lastName" : { - "type" : "string" + "assigned" : { + "type" : "boolean" }, - "subscriptionId" : { - "type" : "string", - "format" : "uuid" + "formattedFinalPrice" : { + "type" : "string" }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "srcPriceCts" : { + "uuid" : { + "type" : "string" + }, + "categoryId" : { "type" : "integer", "format" : "int32" }, @@ -29987,36 +29970,53 @@ "type" : "integer", "format" : "int32" }, - "vatCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "discountCts" : { + "vatCts" : { "type" : "integer", "format" : "int32" }, - "categoryId" : { + "discountCts" : { "type" : "integer", "format" : "int32" }, "ticketsReservationId" : { "type" : "string" }, - "uuid" : { + "eventId" : { + "type" : "integer", + "format" : "int32" + }, + "userLanguage" : { "type" : "string" }, + "tags" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, "lockedAssignment" : { "type" : "boolean" }, "checkedIn" : { "type" : "boolean" }, + "formattedNetPrice" : { + "type" : "string" + }, "creation" : { "type" : "string", "format" : "date-time" }, - "formattedFinalPrice" : { + "extReference" : { "type" : "string" + }, + "subscriptionId" : { + "type" : "string", + "format" : "uuid" } } }, @@ -30687,11 +30687,9 @@ "type" : "string" } }, - "title" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } + "usageType" : { + "type" : "string", + "enum" : [ "ONCE_PER_EVENT", "UNLIMITED" ] }, "vat" : { "type" : "string" @@ -30700,39 +30698,38 @@ "type" : "integer", "format" : "int32" }, + "free" : { + "type" : "boolean" + }, "vatIncluded" : { "type" : "boolean" }, + "fileBlobId" : { + "type" : "string" + }, + "title" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, "termsAndConditionsUrl" : { "type" : "string" }, "privacyPolicyUrl" : { "type" : "string" }, - "validityUnits" : { - "type" : "integer", - "format" : "int32" + "validityType" : { + "type" : "string", + "enum" : [ "STANDARD", "CUSTOM", "NOT_SET" ] }, "validityTimeUnit" : { "type" : "string", "enum" : [ "DAYS", "MONTHS", "YEARS" ] }, - "usageType" : { - "type" : "string", - "enum" : [ "ONCE_PER_EVENT", "UNLIMITED" ] - }, - "free" : { - "type" : "boolean" - }, - "fileBlobId" : { - "type" : "string" - }, - "validityType" : { - "type" : "string", - "enum" : [ "STANDARD", "CUSTOM", "NOT_SET" ] - }, - "formattedPrice" : { - "type" : "string" + "validityUnits" : { + "type" : "integer", + "format" : "int32" }, "assignmentConfiguration" : { "$ref" : "#/components/schemas/AssignmentConfiguration" @@ -30743,6 +30740,9 @@ "canApplySubscriptions" : { "type" : "boolean" }, + "formattedPrice" : { + "type" : "string" + }, "contentLanguages" : { "type" : "array", "items" : { @@ -30760,20 +30760,20 @@ "redirectUrl" : { "type" : "string" }, - "initialized" : { + "redirect" : { "type" : "boolean" }, + "gatewayIdOrNull" : { + "type" : "string" + }, "successful" : { "type" : "boolean" }, "failed" : { "type" : "boolean" }, - "redirect" : { + "initialized" : { "type" : "boolean" - }, - "gatewayIdOrNull" : { - "type" : "string" } } }, @@ -31279,34 +31279,37 @@ "currency" : { "type" : "string" }, - "shortName" : { + "websiteUrl" : { "type" : "string" }, - "title" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, "vat" : { "type" : "string" }, + "free" : { + "type" : "boolean" + }, + "sameDay" : { + "type" : "boolean" + }, "vatIncluded" : { "type" : "boolean" }, - "termsAndConditionsUrl" : { + "fileBlobId" : { "type" : "string" }, - "privacyPolicyUrl" : { - "type" : "string" + "title" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } }, - "free" : { - "type" : "boolean" + "shortName" : { + "type" : "string" }, - "fileBlobId" : { + "termsAndConditionsUrl" : { "type" : "string" }, - "websiteUrl" : { + "privacyPolicyUrl" : { "type" : "string" }, "organizationName" : { @@ -31315,9 +31318,6 @@ "organizationEmail" : { "type" : "string" }, - "sameDay" : { - "type" : "boolean" - }, "datesWithOffset" : { "$ref" : "#/components/schemas/DatesWithTimeZoneOffset" }, @@ -31368,24 +31368,24 @@ "value" : { "$ref" : "#/components/schemas/EventCode" }, - "warnings" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/WarningMessage" - } - }, - "success" : { - "type" : "boolean" - }, "errorCount" : { "type" : "integer", "format" : "int32" }, + "success" : { + "type" : "boolean" + }, "validationErrors" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ErrorDescriptor" } + }, + "warnings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/WarningMessage" + } } } }, @@ -31585,24 +31585,24 @@ "$ref" : "#/components/schemas/Poll" } }, - "warnings" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/WarningMessage" - } - }, - "success" : { - "type" : "boolean" - }, "errorCount" : { "type" : "integer", "format" : "int32" }, + "success" : { + "type" : "boolean" + }, "validationErrors" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ErrorDescriptor" } + }, + "warnings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/WarningMessage" + } } } }, @@ -31651,24 +31651,24 @@ "value" : { "$ref" : "#/components/schemas/PollWithOptions" }, - "warnings" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/WarningMessage" - } - }, - "success" : { - "type" : "boolean" - }, "errorCount" : { "type" : "integer", "format" : "int32" }, + "success" : { + "type" : "boolean" + }, "validationErrors" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ErrorDescriptor" } + }, + "warnings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/WarningMessage" + } } } }, @@ -31884,21 +31884,12 @@ "displayName" : { "type" : "string" }, - "titleAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, - "descriptionAsText" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" + "contentLanguages" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/ContentLanguage" } }, - "publicIdentifier" : { - "type" : "string" - }, "allowedPaymentProxies" : { "type" : "array", "items" : { @@ -31906,12 +31897,6 @@ "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] } }, - "contentLanguages" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/ContentLanguage" - } - }, "begin" : { "type" : "string", "format" : "date-time" @@ -31919,9 +31904,24 @@ "freeOfCharge" : { "type" : "boolean" }, + "publicIdentifier" : { + "type" : "string" + }, "privacyPolicyLinkOrNull" : { "type" : "string" }, + "titleAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, + "descriptionAsText" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, "fileBlobIdIsPresent" : { "type" : "boolean" }, @@ -31952,12 +31952,12 @@ "descriptor" : { "$ref" : "#/components/schemas/SubscriptionDescriptor" }, - "unitPrice" : { - "type" : "number" - }, "availableCount" : { "type" : "integer", "format" : "int32" + }, + "unitPrice" : { + "type" : "number" } } }, @@ -32022,111 +32022,111 @@ "currencyCode" : { "type" : "string" }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "stuck" : { - "type" : "boolean" - }, - "tags" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "assigned" : { - "type" : "boolean" - }, - "transaction" : { - "$ref" : "#/components/schemas/Transaction" - }, - "email" : { + "firstName" : { "type" : "string" }, - "userLanguage" : { + "lastName" : { "type" : "string" }, - "eventId" : { - "type" : "integer", - "format" : "int32" - }, - "firstName" : { + "email" : { "type" : "string" }, - "lastName" : { - "type" : "string" + "assigned" : { + "type" : "boolean" }, - "subscriptionId" : { - "type" : "string", - "format" : "uuid" + "formattedFinalPrice" : { + "type" : "string" }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "srcPriceCts" : { + "uuid" : { + "type" : "string" + }, + "categoryId" : { "type" : "integer", "format" : "int32" }, - "finalPrice" : { - "type" : "number" - }, "finalPriceCts" : { "type" : "integer", "format" : "int32" }, - "vatCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "discountCts" : { + "vatCts" : { "type" : "integer", "format" : "int32" }, - "categoryId" : { + "discountCts" : { "type" : "integer", "format" : "int32" }, "ticketsReservationId" : { "type" : "string" }, - "uuid" : { + "eventId" : { + "type" : "integer", + "format" : "int32" + }, + "userLanguage" : { "type" : "string" }, + "transaction" : { + "$ref" : "#/components/schemas/Transaction" + }, + "finalPrice" : { + "type" : "number" + }, + "tags" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, "lockedAssignment" : { "type" : "boolean" }, "checkedIn" : { "type" : "boolean" }, + "formattedNetPrice" : { + "type" : "string" + }, "creation" : { "type" : "string", "format" : "date-time" }, - "formattedFinalPrice" : { + "extReference" : { "type" : "string" }, - "transactionTimestamp" : { + "subscriptionId" : { "type" : "string", - "format" : "date-time" + "format" : "uuid" }, "paid" : { "type" : "boolean" }, + "stuck" : { + "type" : "boolean" + }, + "transactionTimestamp" : { + "type" : "string", + "format" : "date-time" + }, "pending" : { "type" : "boolean" }, - "netPrice" : { + "taxablePrice" : { "type" : "number" }, - "taxablePrice" : { + "netPrice" : { "type" : "number" } } @@ -32253,11 +32253,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -32270,50 +32270,39 @@ "currencyCode" : { "type" : "string" }, - "formattedNetPrice" : { - "type" : "string" - }, - "extReference" : { - "type" : "string" - }, "status" : { "type" : "string", "enum" : [ "FREE", "PENDING", "TO_BE_PAID", "ACQUIRED", "CANCELLED", "CHECKED_IN", "EXPIRED", "INVALIDATED", "RELEASED", "PRE_RESERVED" ] }, - "tags" : { - "type" : "array", - "items" : { + "additionalFields" : { + "type" : "object", + "additionalProperties" : { "type" : "string" } }, - "assigned" : { - "type" : "boolean" - }, - "email" : { + "firstName" : { "type" : "string" }, - "userLanguage" : { + "lastName" : { "type" : "string" }, - "eventId" : { - "type" : "integer", - "format" : "int32" - }, - "firstName" : { + "email" : { "type" : "string" }, - "lastName" : { - "type" : "string" + "assigned" : { + "type" : "boolean" }, - "subscriptionId" : { - "type" : "string", - "format" : "uuid" + "formattedFinalPrice" : { + "type" : "string" }, "vatStatus" : { "type" : "string", "enum" : [ "NONE", "INCLUDED", "NOT_INCLUDED", "INCLUDED_EXEMPT", "NOT_INCLUDED_EXEMPT", "CUSTOM_INCLUDED_EXEMPT", "CUSTOM_NOT_INCLUDED_EXEMPT", "INCLUDED_NOT_CHARGED", "NOT_INCLUDED_NOT_CHARGED" ] }, - "srcPriceCts" : { + "uuid" : { + "type" : "string" + }, + "categoryId" : { "type" : "integer", "format" : "int32" }, @@ -32321,42 +32310,53 @@ "type" : "integer", "format" : "int32" }, - "vatCts" : { + "srcPriceCts" : { "type" : "integer", "format" : "int32" }, - "discountCts" : { + "vatCts" : { "type" : "integer", "format" : "int32" }, - "categoryId" : { + "discountCts" : { "type" : "integer", "format" : "int32" }, "ticketsReservationId" : { "type" : "string" }, - "uuid" : { + "eventId" : { + "type" : "integer", + "format" : "int32" + }, + "userLanguage" : { "type" : "string" }, + "tags" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, "lockedAssignment" : { "type" : "boolean" }, "checkedIn" : { "type" : "boolean" }, + "formattedNetPrice" : { + "type" : "string" + }, "creation" : { "type" : "string", "format" : "date-time" }, - "formattedFinalPrice" : { + "extReference" : { "type" : "string" }, - "additionalFields" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } + "subscriptionId" : { + "type" : "string", + "format" : "uuid" } } }, @@ -32391,12 +32391,29 @@ "type" : "string", "enum" : [ "WAITING", "RETRY", "IN_PROCESS", "SENT", "ERROR" ] }, + "organizationId" : { + "type" : "integer", + "format" : "int32" + }, + "requestTimestamp" : { + "type" : "string", + "format" : "date-time" + }, "attempts" : { "type" : "integer", "format" : "int32" }, - "checksum" : { - "type" : "string" + "subscriptionDescriptorId" : { + "type" : "string", + "format" : "uuid" + }, + "eventId" : { + "type" : "integer", + "format" : "int32" + }, + "purchaseContextType" : { + "type" : "string", + "enum" : [ "subscription", "event" ] }, "recipient" : { "type" : "string" @@ -32416,25 +32433,8 @@ "attachments" : { "type" : "string" }, - "purchaseContextType" : { - "type" : "string", - "enum" : [ "subscription", "event" ] - }, - "subscriptionDescriptorId" : { - "type" : "string", - "format" : "uuid" - }, - "eventId" : { - "type" : "integer", - "format" : "int32" - }, - "organizationId" : { - "type" : "integer", - "format" : "int32" - }, - "requestTimestamp" : { - "type" : "string", - "format" : "date-time" + "checksum" : { + "type" : "string" }, "sentTimestamp" : { "type" : "string", @@ -32468,14 +32468,14 @@ "type" : "integer", "format" : "int32" }, - "participationPercentage" : { - "type" : "string" - }, "optionStatistics" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/StatisticDetail" } + }, + "participationPercentage" : { + "type" : "string" } } }, @@ -32543,10 +32543,11 @@ "enabled" : { "type" : "boolean" }, - "description" : { - "type" : "string" + "validTo" : { + "type" : "string", + "format" : "date-time" }, - "username" : { + "description" : { "type" : "string" }, "firstName" : { @@ -32558,13 +32559,12 @@ "emailAddress" : { "type" : "string" }, + "username" : { + "type" : "string" + }, "validToEpochSecond" : { "type" : "integer", "format" : "int64" - }, - "validTo" : { - "type" : "string", - "format" : "date-time" } } }, @@ -32637,11 +32637,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -32684,11 +32684,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -32797,11 +32797,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -32867,11 +32867,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -32941,11 +32941,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -33068,48 +33068,42 @@ "currencyCode" : { "type" : "string" }, - "dynamic" : { - "type" : "boolean" - }, "description" : { "type" : "string" }, - "formattedStart" : { - "type" : "string" + "currentlyValid" : { + "type" : "boolean" }, - "formattedEnd" : { + "formattedDiscountAmount" : { "type" : "string" }, - "formattedDiscountAmount" : { + "categories" : { + "uniqueItems" : true, + "type" : "array", + "items" : { + "type" : "integer", + "format" : "int32" + } + }, + "promoCode" : { "type" : "string" }, - "eventId" : { + "organizationId" : { "type" : "integer", "format" : "int32" }, - "organizationId" : { + "eventId" : { "type" : "integer", "format" : "int32" }, - "promoCode" : { - "type" : "string" - }, - "utcStart" : { - "type" : "string", - "format" : "date-time" - }, - "utcEnd" : { + "discountType" : { "type" : "string", - "format" : "date-time" + "enum" : [ "FIXED_AMOUNT", "PERCENTAGE", "FIXED_AMOUNT_RESERVATION", "NONE" ] }, "discountAmount" : { "type" : "integer", "format" : "int32" }, - "discountType" : { - "type" : "string", - "enum" : [ "FIXED_AMOUNT", "PERCENTAGE", "FIXED_AMOUNT_RESERVATION", "NONE" ] - }, "codeType" : { "type" : "string", "enum" : [ "DISCOUNT", "ACCESS", "DYNAMIC" ] @@ -33118,29 +33112,35 @@ "type" : "integer", "format" : "int32" }, - "maxUsage" : { - "type" : "integer", - "format" : "int32" + "fixedAmount" : { + "type" : "boolean" }, - "categories" : { - "uniqueItems" : true, - "type" : "array", - "items" : { - "type" : "integer", - "format" : "int32" - } + "expired" : { + "type" : "boolean" }, - "currentlyValid" : { + "dynamic" : { "type" : "boolean" }, "emailReference" : { "type" : "string" }, - "expired" : { - "type" : "boolean" + "utcStart" : { + "type" : "string", + "format" : "date-time" }, - "fixedAmount" : { - "type" : "boolean" + "utcEnd" : { + "type" : "string", + "format" : "date-time" + }, + "maxUsage" : { + "type" : "integer", + "format" : "int32" + }, + "formattedStart" : { + "type" : "string" + }, + "formattedEnd" : { + "type" : "string" } } }, @@ -33427,6 +33427,13 @@ "type" : "string", "enum" : [ "DRAFT", "PUBLIC", "DISABLED" ] }, + "allowedPaymentProxies" : { + "type" : "array", + "items" : { + "type" : "string", + "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] + } + }, "notSoldTickets" : { "type" : "integer", "format" : "int32" @@ -33435,51 +33442,36 @@ "type" : "integer", "format" : "int32" }, - "pendingTickets" : { - "type" : "integer", - "format" : "int32" - }, - "dynamicAllocation" : { - "type" : "integer", - "format" : "int32" - }, - "releasedTickets" : { + "availableSeats" : { "type" : "integer", "format" : "int32" }, - "formattedEnd" : { - "type" : "string" - }, - "shortName" : { + "fileBlobId" : { "type" : "string" }, "organizationId" : { "type" : "integer", "format" : "int32" }, - "allowedPaymentProxies" : { - "type" : "array", - "items" : { - "type" : "string", - "enum" : [ "STRIPE", "ON_SITE", "OFFLINE", "NONE", "ADMIN", "PAYPAL", "MOLLIE", "SAFERPAY" ] - } - }, - "fileBlobId" : { + "shortName" : { "type" : "string" }, - "notAllocatedTickets" : { + "checkedInTickets" : { "type" : "integer", "format" : "int32" }, - "availableSeats" : { + "dynamicAllocation" : { "type" : "integer", "format" : "int32" }, - "checkedInTickets" : { + "expired" : { + "type" : "boolean" + }, + "notAllocatedTickets" : { "type" : "integer", "format" : "int32" }, - "expired" : { + "visibleForCurrentUser" : { "type" : "boolean" }, "warningNeeded" : { @@ -33488,11 +33480,19 @@ "formattedBegin" : { "type" : "string" }, - "visibleForCurrentUser" : { - "type" : "boolean" - }, "displayStatistics" : { "type" : "boolean" + }, + "pendingTickets" : { + "type" : "integer", + "format" : "int32" + }, + "releasedTickets" : { + "type" : "integer", + "format" : "int32" + }, + "formattedEnd" : { + "type" : "string" } } }, @@ -33511,22 +33511,20 @@ "timeZone" : { "type" : "string" }, - "url" : { - "type" : "string" - }, - "descriptions" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/PublicEventDescription" - } + "apiVersion" : { + "type" : "integer", + "format" : "int32" }, - "oneDay" : { - "type" : "boolean" + "end" : { + "type" : "string" }, "begin" : { "type" : "string" }, - "end" : { + "url" : { + "type" : "string" + }, + "imageUrl" : { "type" : "string" }, "latitude" : { @@ -33535,12 +33533,14 @@ "longitude" : { "type" : "string" }, - "imageUrl" : { - "type" : "string" + "descriptions" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/PublicEventDescription" + } }, - "apiVersion" : { - "type" : "integer", - "format" : "int32" + "oneDay" : { + "type" : "boolean" } } }, @@ -33634,10 +33634,10 @@ "key" : { "type" : "string" }, - "left" : { + "right" : { "type" : "string" }, - "right" : { + "left" : { "type" : "string" } } @@ -33726,12 +33726,15 @@ "type" : "integer", "format" : "int32" }, - "inputType" : { - "type" : "string" + "checkboxField" : { + "type" : "boolean" }, "countryField" : { "type" : "boolean" }, + "inputType" : { + "type" : "string" + }, "inputField" : { "type" : "boolean" }, @@ -33741,9 +33744,6 @@ "selectField" : { "type" : "boolean" }, - "checkboxField" : { - "type" : "boolean" - }, "euVat" : { "type" : "boolean" }, @@ -33788,10 +33788,13 @@ "type" : "integer", "format" : "int32" }, - "inputType" : { - "type" : "string" + "editable" : { + "type" : "boolean" }, - "disabledValues" : { + "checkboxField" : { + "type" : "boolean" + }, + "restrictedValues" : { "type" : "array", "items" : { "type" : "string" @@ -33801,37 +33804,37 @@ "type" : "integer", "format" : "int32" }, - "minLength" : { + "eventId" : { "type" : "integer", "format" : "int32" }, - "maxLength" : { + "additionalServiceId" : { "type" : "integer", "format" : "int32" }, "required" : { "type" : "boolean" }, - "eventId" : { + "maxLength" : { "type" : "integer", "format" : "int32" }, - "additionalServiceId" : { + "minLength" : { "type" : "integer", "format" : "int32" }, "countryField" : { "type" : "boolean" }, - "restrictedValues" : { + "inputType" : { + "type" : "string" + }, + "disabledValues" : { "type" : "array", "items" : { "type" : "string" } }, - "editable" : { - "type" : "boolean" - }, "inputField" : { "type" : "boolean" }, @@ -33841,9 +33844,6 @@ "selectField" : { "type" : "boolean" }, - "checkboxField" : { - "type" : "boolean" - }, "euVat" : { "type" : "boolean" }, @@ -33991,43 +33991,40 @@ "type" : "string", "enum" : [ "subscription", "event" ] }, - "title" : { - "type" : "object", - "additionalProperties" : { - "type" : "string" - } - }, - "publicIdentifier" : { - "type" : "string" - }, - "free" : { - "type" : "boolean" - }, "contentLanguages" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ContentLanguage" } }, - "freeOfCharge" : { + "fileBlobIdIsPresent" : { "type" : "boolean" }, - "online" : { - "type" : "boolean" + "regularPrice" : { + "type" : "number" }, "sameDay" : { "type" : "boolean" }, - "isOnline" : { + "title" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, + "freeOfCharge" : { "type" : "boolean" }, - "regularPrice" : { - "type" : "number" + "publicIdentifier" : { + "type" : "string" }, - "imageIsPresent" : { + "online" : { "type" : "boolean" }, - "fileBlobIdIsPresent" : { + "free" : { + "type" : "boolean" + }, + "imageIsPresent" : { "type" : "boolean" }, "multiplePaymentMethods" : { @@ -34051,6 +34048,9 @@ "type" : "integer", "format" : "int32" }, + "isOnline" : { + "type" : "boolean" + }, "firstContentLanguage" : { "$ref" : "#/components/schemas/ContentLanguage" } @@ -34212,11 +34212,11 @@ "success" : { "type" : "boolean" }, - "formattedErrors" : { - "type" : "string" - }, "firstErrorOrNull" : { "$ref" : "#/components/schemas/ErrorCode" + }, + "formattedErrors" : { + "type" : "string" } } }, @@ -34273,7 +34273,7 @@ }, "configurationKey" : { "type" : "string", - "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] + "enum" : [ "NOT_RECOGNIZED", "INIT_COMPLETED", "SYSTEM_API_KEY", "SHOW_PROJECT_BANNER", "SUPPORTED_LANGUAGES", "BASE_URL", "GLOBAL_PRIVACY_POLICY", "GLOBAL_TERMS", "ANNOUNCEMENT_BANNER_CONTENT", "MAPS_PROVIDER", "MAPS_CLIENT_API_KEY", "MAPS_HERE_APP_ID", "MAPS_HERE_APP_CODE", "MAPS_HERE_API_KEY", "RECAPTCHA_API_KEY", "RECAPTCHA_SECRET", "ENABLE_CAPTCHA_FOR_LOGIN", "DISPLAY_STATS_IN_EVENT_DETAIL", "DEMO_MODE_ACCOUNT_EXPIRATION_DAYS", "PLATFORM_MODE_ENABLED", "PLATFORM_FEE", "PLATFORM_FIXED_FEE", "PLATFORM_PERCENTAGE_FEE", "PLATFORM_MINIMUM_FEE", "PLATFORM_MAXIMUM_FEE", "PAYMENT_METHODS_BLACKLIST", "STRIPE_CC_ENABLED", "STRIPE_PUBLIC_KEY", "STRIPE_SECRET_KEY", "STRIPE_CONNECT_CLIENT_ID", "STRIPE_CONNECT_CALLBACK", "STRIPE_WEBHOOK_KEY", "STRIPE_WEBHOOK_PAYMENT_KEY", "STRIPE_CONNECTED_ID", "STRIPE_ENABLE_SCA", "SAFERPAY_ENABLED", "SAFERPAY_LIVE_MODE", "SAFERPAY_API_USERNAME", "SAFERPAY_API_PASSWORD", "SAFERPAY_CUSTOMER_ID", "SAFERPAY_TERMINAL_ID", "SPECIAL_PRICE_CODE_LENGTH", "MAX_AMOUNT_OF_TICKETS_BY_RESERVATION", "ASSIGNMENT_REMINDER_START", "ASSIGNMENT_REMINDER_INTERVAL", "OPTIONAL_DATA_REMINDER_ENABLED", "RESERVATION_TIMEOUT", "RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT", "NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS", "DISPLAY_TICKETS_LEFT_INDICATOR", "ENABLE_CAPTCHA_FOR_TICKET_SELECTION", "DISPLAY_EXPIRED_CATEGORIES", "DISPLAY_DISCOUNT_CODE_BOX", "USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL", "ENABLE_CUSTOMER_REFERENCE", "ENABLE_ATTENDEE_AUTOCOMPLETE", "FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION", "SEND_TICKETS_AUTOMATICALLY", "ALLOW_TICKET_DOWNLOAD", "SEND_RESERVATION_EMAIL_IF_NECESSARY", "ENABLE_TICKET_TRANSFER", "ALLOW_FREE_TICKETS_CANCELLATION", "INCLUDE_CHECK_IN_URL_ICAL", "MAILER_TYPE", "MAX_EMAIL_PER_CYCLE", "MAIL_REPLY_TO", "MAIL_SET_ORG_REPLY_TO", "MAIL_SYSTEM_NOTIFICATION_CC", "MAIL_FOOTER", "SMTP_HOST", "SMTP_PORT", "SMTP_PROTOCOL", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_FROM_EMAIL", "SMTP_PROPERTIES", "BANK_TRANSFER_ENABLED", "DEFERRED_BANK_TRANSFER_ENABLED", "SHOW_ONLY_BASIC_INSTRUCTIONS", "DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL", "OFFLINE_PAYMENT_DAYS", "OFFLINE_REMINDER_HOURS", "ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS", "BANK_ACCOUNT_NR", "BANK_ACCOUNT_OWNER", "AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT", "PARTIAL_RESERVATION_ID_LENGTH", "REVOLUT_ENABLED", "REVOLUT_MANUAL_REVIEW", "REVOLUT_LIVE_MODE", "REVOLUT_API_KEY", "MAILGUN_KEY", "MAILGUN_DOMAIN", "MAILGUN_FROM", "MAILGUN_EU", "SENDGRID_API_KEY", "SENDGRID_FROM", "MAILJET_APIKEY_PUBLIC", "MAILJET_APIKEY_PRIVATE", "MAILJET_FROM", "GOOGLE_ANALYTICS_KEY", "GOOGLE_ANALYTICS_ANONYMOUS_MODE", "ENABLE_WAITING_QUEUE", "ENABLE_PRE_REGISTRATION", "ENABLE_WAITING_QUEUE_NOTIFICATION", "WAITING_QUEUE_RESERVATION_TIMEOUT", "STOP_WAITING_QUEUE_SUBSCRIPTIONS", "ENABLE_HTML_EMAILS", "MAIL_ATTEMPTS_COUNT", "PAYPAL_ENABLED", "PAYPAL_CLIENT_ID", "PAYPAL_CLIENT_SECRET", "PAYPAL_LIVE_MODE", "PAYPAL_DEMO_MODE_USERNAME", "PAYPAL_DEMO_MODE_PASSWORD", "MOLLIE_CC_ENABLED", "MOLLIE_API_KEY", "MOLLIE_CONNECT_CLIENT_ID", "MOLLIE_CONNECT_REFRESH_TOKEN", "MOLLIE_CONNECT_CLIENT_SECRET", "MOLLIE_CONNECT_CALLBACK", "MOLLIE_CONNECT_PROFILE_ID", "MOLLIE_CONNECT_LIVE_MODE", "ON_SITE_ENABLED", "SEND_TICKETS_AFTER_IMPORT_ATTENDEE", "CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE", "VAT_NR", "INVOICE_NUMBER_PATTERN", "INVOICE_ADDRESS", "USE_INVOICE_NUMBER_AS_ID", "VAT_NUMBER_IS_REQUIRED", "GENERATE_ONLY_INVOICE", "REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE", "ENABLE_ITALY_E_INVOICING", "ITALY_E_INVOICING_SEND_PROFORMA", "ENABLE_EU_VAT_DIRECTIVE", "ENABLE_REVERSE_CHARGE_ONLINE", "ENABLE_REVERSE_CHARGE_IN_PERSON", "ENABLE_VIES_VALIDATION", "APPLY_VAT_FOREIGN_BUSINESS", "COUNTRY_OF_BUSINESS", "EU_COUNTRIES_LIST", "EU_VAT_API_ADDRESS", "APPLY_TAX_TO_CATEGORY", "ENABLE_PASS", "PASSBOOK_TYPE_IDENTIFIER", "PASSBOOK_TEAM_IDENTIFIER", "PASSBOOK_KEYSTORE", "PASSBOOK_KEYSTORE_PASSWORD", "PASSBOOK_PRIVATE_KEY_ALIAS", "CHECK_IN_STATS", "ALFIO_PI_INTEGRATION_ENABLED", "OFFLINE_CHECKIN_ENABLED", "LABEL_PRINTING_ENABLED", "LABEL_LAYOUT", "CHECK_IN_COLOR_CONFIGURATION", "SECURITY_CSP_REPORT_ENABLED", "SECURITY_CSP_REPORT_URI", "EMBED_ALLOWED_ORIGINS", "EMBED_POST_MESSAGE_ORIGIN", "TRANSLATION_OVERRIDE", "BASE_CUSTOM_CSS", "EVENT_CUSTOM_CSS", "DESCRIPTION_MAXLENGTH", "OPENID_PUBLIC_ENABLED", "OPENID_CONFIGURATION_JSON", "GENERATE_TICKETS_FOR_SUBSCRIPTIONS" ] }, "configurationPathLevel" : { "type" : "string", @@ -34312,10 +34312,10 @@ "key" : { "type" : "string" }, - "left" : { + "right" : { "type" : "string" }, - "right" : { + "left" : { "type" : "string" } } From 4d49956da4d73c81d745f5378c7a43c396e0c52c Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Mon, 17 Apr 2023 07:22:49 +0200 Subject: [PATCH 184/218] add italian translation --- src/main/resources/alfio/i18n/public_it.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/alfio/i18n/public_it.properties b/src/main/resources/alfio/i18n/public_it.properties index 7bc1789f2d..2b1afb0bce 100644 --- a/src/main/resources/alfio/i18n/public_it.properties +++ b/src/main/resources/alfio/i18n/public_it.properties @@ -187,6 +187,7 @@ invoice.payment-instruction = Indicazioni per il pagamento invoice.payment-instruction-no-later-than = Per confermare la tua prenotazione, dobbiamo ricevere il pagamento entro il {0}. invoice.payment-reason = Specificando {0} quale causale del pagamento. invoice.payment-to = Pagamento a\: +invoice.proforma = Fattura Proforma invoice.refund = Questa fattura è stata aggiornata dopo la cancellazione di uno o più biglietti ed il rimborso di {0}. invoice.refund.line-item = Rimborso invoice.regards = Cordiali saluti, @@ -202,6 +203,7 @@ invoice.vat-invoice = Fattura # please do not translate. This is strictly related to the Italian market invoice.vat-not-added = {0} non inclusa come da direttiva sulla Scissione dei Pagamenti invoice.vat-voided = {0} omessa, come da direttive UE +# Fuzzy link.new-tab = (si apre in un nuovo tab) locale = it my-orders.confirmation-date = Data di conferma From b4d7bb495ec9f887845590f68cb63878213b4b5d Mon Sep 17 00:00:00 2001 From: Lorena Mondini <60662357+Lorslux@users.noreply.github.com> Date: Fri, 28 Apr 2023 14:45:15 +0200 Subject: [PATCH 185/218] Admin frontend UI organization : list create - edit (#1212) * Added Load Organizations's table * Add table, organization component * Added news/edit * Functionality edit * added title edit or new * added form * added configuration service * added formGroup * added save button * added redirect * added update * UI style, input validator * clean up * revert docker compose change --- .../access-control.component.html | 1 + .../access-control.component.scss | 0 .../access-control.component.ts | 15 +++ .../admin/src/app/app-routing.module.ts | 19 ++++ .../projects/admin/src/app/app.component.ts | 2 +- frontend/projects/admin/src/app/app.module.ts | 9 ++ .../src/app/dashboard/dashboard.module.ts | 1 + .../app/missing-org/missing-org.component.ts | 1 - .../admin/src/app/model/instance-settings.ts | 4 + .../org-selector/org-selector.component.html | 45 ++++++-- .../org-selector/org-selector.component.ts | 2 + .../organization-edit.component.html | 106 ++++++++++++++++++ .../organization-edit.component.scss | 0 .../organization-edit.component.ts | 78 +++++++++++++ .../organizations.component.html | 40 +++++++ .../organizations.component.scss | 0 .../organizations/organizations.component.ts | 19 ++++ .../src/app/shared/configuration.service.ts | 17 +++ .../projects/admin/src/app/shared/icons.ts | 7 +- .../src/app/shared/organization.service.ts | 26 ++++- .../section-dashboard.component.ts | 3 + .../admin/src/app/svg/add-circle-new.ts | 4 + frontend/projects/admin/src/app/svg/edit.ts | 4 + .../admin/src/assets/svg/add-circle-new.svg | 1 + .../projects/admin/src/assets/svg/edit.svg | 1 + 25 files changed, 386 insertions(+), 19 deletions(-) create mode 100644 frontend/projects/admin/src/app/access-control/access-control.component.html create mode 100644 frontend/projects/admin/src/app/access-control/access-control.component.scss create mode 100644 frontend/projects/admin/src/app/access-control/access-control.component.ts create mode 100644 frontend/projects/admin/src/app/model/instance-settings.ts create mode 100644 frontend/projects/admin/src/app/organization-edit/organization-edit.component.html create mode 100644 frontend/projects/admin/src/app/organization-edit/organization-edit.component.scss create mode 100644 frontend/projects/admin/src/app/organization-edit/organization-edit.component.ts create mode 100644 frontend/projects/admin/src/app/organizations/organizations.component.html create mode 100644 frontend/projects/admin/src/app/organizations/organizations.component.scss create mode 100644 frontend/projects/admin/src/app/organizations/organizations.component.ts create mode 100644 frontend/projects/admin/src/app/shared/configuration.service.ts create mode 100644 frontend/projects/admin/src/app/svg/add-circle-new.ts create mode 100644 frontend/projects/admin/src/app/svg/edit.ts create mode 100644 frontend/projects/admin/src/assets/svg/add-circle-new.svg create mode 100644 frontend/projects/admin/src/assets/svg/edit.svg diff --git a/frontend/projects/admin/src/app/access-control/access-control.component.html b/frontend/projects/admin/src/app/access-control/access-control.component.html new file mode 100644 index 0000000000..46e0673e93 --- /dev/null +++ b/frontend/projects/admin/src/app/access-control/access-control.component.html @@ -0,0 +1 @@ +

access-control works!

diff --git a/frontend/projects/admin/src/app/access-control/access-control.component.scss b/frontend/projects/admin/src/app/access-control/access-control.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/access-control/access-control.component.ts b/frontend/projects/admin/src/app/access-control/access-control.component.ts new file mode 100644 index 0000000000..6101158ba7 --- /dev/null +++ b/frontend/projects/admin/src/app/access-control/access-control.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-access-control', + templateUrl: './access-control.component.html', + styleUrls: ['./access-control.component.scss'] +}) +export class AccessControlComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/app-routing.module.ts b/frontend/projects/admin/src/app/app-routing.module.ts index e95030080c..e04c743c87 100644 --- a/frontend/projects/admin/src/app/app-routing.module.ts +++ b/frontend/projects/admin/src/app/app-routing.module.ts @@ -1,6 +1,9 @@ import {NgModule} from '@angular/core'; import {PreloadAllModules, RouterModule, Routes} from '@angular/router'; import {MissingOrgComponent} from './missing-org/missing-org.component'; +import { OrganizationsComponent } from './organizations/organizations.component'; +import { OrganizationEditComponent } from './organization-edit/organization-edit.component'; +import { AccessControlComponent } from './access-control/access-control.component'; const routes: Routes = [ { @@ -15,6 +18,22 @@ const routes: Routes = [ path: 'authentication', loadChildren: () => import('./authentication/authentication.module').then(m => m.AuthenticationModule) }, + { + path: 'organizations', + component: OrganizationsComponent, + }, + { + path: 'organizations/new', + component: OrganizationEditComponent, + }, + { + path: 'organizations/:organizationId/edit', + component: OrganizationEditComponent, + }, + { + path: 'access-control', + component: AccessControlComponent, + }, { path: '', component: MissingOrgComponent, diff --git a/frontend/projects/admin/src/app/app.component.ts b/frontend/projects/admin/src/app/app.component.ts index ef3488c391..6349bf5a23 100644 --- a/frontend/projects/admin/src/app/app.component.ts +++ b/frontend/projects/admin/src/app/app.component.ts @@ -44,7 +44,7 @@ export class AppComponent implements OnInit { } public openOrgSelector(): void { - const modalRef = this.modalService.open(OrgSelectorComponent); + const modalRef = this.modalService.open(OrgSelectorComponent, { size: 'lg' }); const selector: OrgSelectorComponent = modalRef.componentInstance selector.organizations$ = this.organizations$; selector.organizationId$ = this.organizationId$; diff --git a/frontend/projects/admin/src/app/app.module.ts b/frontend/projects/admin/src/app/app.module.ts index 5acaee4f1c..b140d69edf 100644 --- a/frontend/projects/admin/src/app/app.module.ts +++ b/frontend/projects/admin/src/app/app.module.ts @@ -19,6 +19,11 @@ import {SectionDashboardComponent} from "./shared/section-dashboard/section-dash import {SharedModule} from "./shared/shared.module"; import {HttpLoginInterceptor, redirectToLogin} from "./shared/http-login.interceptor"; import {AlfioCommonModule} from "common"; +import { OrganizationsComponent } from './organizations/organizations.component'; +import { OrganizationEditComponent } from './organization-edit/organization-edit.component'; +import { ReactiveFormsModule } from '@angular/forms'; +import { AccessControlComponent } from './access-control/access-control.component'; + export function RedirectToLoginIfNeeded(userService: UserService, router: Router): () => Promise { return async () => { @@ -40,12 +45,16 @@ export function HttpLoaderFactory(http: HttpClient) { AppComponent, MissingOrgComponent, OrgSelectorComponent, + OrganizationsComponent, + OrganizationEditComponent, + AccessControlComponent, ], imports: [ BrowserModule, AppRoutingModule, AuthenticationModule, HttpClientModule, + ReactiveFormsModule, HttpClientXsrfModule.withOptions({ cookieName: 'XSRF-TOKEN', headerName: 'X-CSRF-TOKEN', diff --git a/frontend/projects/admin/src/app/dashboard/dashboard.module.ts b/frontend/projects/admin/src/app/dashboard/dashboard.module.ts index 459cf10ad8..73b5c8e446 100644 --- a/frontend/projects/admin/src/app/dashboard/dashboard.module.ts +++ b/frontend/projects/admin/src/app/dashboard/dashboard.module.ts @@ -25,6 +25,7 @@ import {FilterButtonComponent} from '../shared/filter-button/filter-button.compo { path: 'subscriptions', component: SubscriptionsComponent }, { path: 'organization-info', component: OrganizationInfoComponent }, { path: 'groups', component: GroupsComponent }, + ]), SvgIconComponent, FilterButtonComponent, diff --git a/frontend/projects/admin/src/app/missing-org/missing-org.component.ts b/frontend/projects/admin/src/app/missing-org/missing-org.component.ts index c0d094be90..9b1f3c15dd 100644 --- a/frontend/projects/admin/src/app/missing-org/missing-org.component.ts +++ b/frontend/projects/admin/src/app/missing-org/missing-org.component.ts @@ -22,5 +22,4 @@ export class MissingOrgComponent implements OnInit { } }); } - } diff --git a/frontend/projects/admin/src/app/model/instance-settings.ts b/frontend/projects/admin/src/app/model/instance-settings.ts new file mode 100644 index 0000000000..1cf4ce9e8d --- /dev/null +++ b/frontend/projects/admin/src/app/model/instance-settings.ts @@ -0,0 +1,4 @@ +export interface InstanceSetting { + descriptionMaxLength: number; + baseUrl: string; +} diff --git a/frontend/projects/admin/src/app/org-selector/org-selector.component.html b/frontend/projects/admin/src/app/org-selector/org-selector.component.html index 90e8f3aa29..9e6fd159d7 100644 --- a/frontend/projects/admin/src/app/org-selector/org-selector.component.html +++ b/frontend/projects/admin/src/app/org-selector/org-selector.component.html @@ -1,14 +1,39 @@ -