fix: platform membership fixes (#740)
This commit is contained in:
parent
97a839c491
commit
eea58804cd
43 changed files with 1668 additions and 35 deletions
|
|
@ -35,6 +35,10 @@ App\Entity\User:
|
||||||
devAccount: true
|
devAccount: true
|
||||||
address: '@address_loic'
|
address: '@address_loic'
|
||||||
avatar: '7c732ddb-9c13-45eb-aea0-e614f2340e6d.jpg'
|
avatar: '7c732ddb-9c13-45eb-aea0-e614f2340e6d.jpg'
|
||||||
|
membershipPaid: true
|
||||||
|
platformOffer: '@platform_offer_1'
|
||||||
|
startAt: <date_create_immutable('-1 year - 1 day')>
|
||||||
|
endAt: <date_create_immutable('-1 day')>
|
||||||
|
|
||||||
admin_kevin (extends admin_template):
|
admin_kevin (extends admin_template):
|
||||||
id: <uuid('1ed69804-eeb9-6c32-990b-632c3a6846ba')>
|
id: <uuid('1ed69804-eeb9-6c32-990b-632c3a6846ba')>
|
||||||
|
|
@ -42,8 +46,11 @@ App\Entity\User:
|
||||||
firstname: 'Kevin'
|
firstname: 'Kevin'
|
||||||
lastname: 'Pirouet'
|
lastname: 'Pirouet'
|
||||||
avatar: '7c732ddb-9c13-45eb-aea0-e614f2340e6d.jpg'
|
avatar: '7c732ddb-9c13-45eb-aea0-e614f2340e6d.jpg'
|
||||||
membershipPaid: true
|
|
||||||
type: !php/enum App\Enum\User\UserType::ADMIN
|
type: !php/enum App\Enum\User\UserType::ADMIN
|
||||||
|
membershipPaid: true
|
||||||
|
platformOffer: '@platform_offer_1'
|
||||||
|
startAt: <date_create_immutable('-1 year + 7 day')>
|
||||||
|
endAt: <date_create_immutable('+7 day midnight')>
|
||||||
roles: [ !php/const App\Entity\User::ROLE_ADMIN, !php/const App\Entity\User::MEMBERSHIP_PAID]
|
roles: [ !php/const App\Entity\User::ROLE_ADMIN, !php/const App\Entity\User::MEMBERSHIP_PAID]
|
||||||
|
|
||||||
admin_apes (extends admin_template):
|
admin_apes (extends admin_template):
|
||||||
|
|
|
||||||
148
helm/chart/templates/cronjobs/cronjobEndPlatformMembership.yaml
Normal file
148
helm/chart/templates/cronjobs/cronjobEndPlatformMembership.yaml
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
{{- if .Values.dailyCronjobs.enabled }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: {{ include "plateforme-ebs" . }}-cronjob-end-membership
|
||||||
|
labels:
|
||||||
|
{{- include "plateforme-ebs.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
schedule: '15 1 * * *'
|
||||||
|
jobTemplate:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rollme: {{ randAlphaNum 5 | quote }}
|
||||||
|
labels:
|
||||||
|
{{- include "plateforme-ebs.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "plateforme-ebs.serviceAccountName" . }}
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}-cronjob-end-membership
|
||||||
|
image: "{{ .Values.php.image.repository }}:{{ .Values.php.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.php.image.pullPolicy }}
|
||||||
|
command: ['/bin/sh', '-c']
|
||||||
|
args: ['bin/console app:end-platform-membership --env=prod']
|
||||||
|
env:
|
||||||
|
- name: API_ENTRYPOINT_HOST
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-host
|
||||||
|
- name: JWT_PASSPHRASE
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-passphrase
|
||||||
|
- name: JWT_PUBLIC_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-public-key
|
||||||
|
- name: JWT_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-secret-key
|
||||||
|
- name: TRUSTED_HOSTS
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-trusted-hosts
|
||||||
|
- name: TRUSTED_PROXIES
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-trusted-proxies
|
||||||
|
- name: APP_ENV
|
||||||
|
value: "prod"
|
||||||
|
- name: APP_DEBUG
|
||||||
|
value: "0"
|
||||||
|
- name: APP_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-app-secret
|
||||||
|
- name: CORS_ALLOW_ORIGIN
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-cors-allow-origin
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: database-url
|
||||||
|
- name: MERCURE_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-url
|
||||||
|
- name: MERCURE_PUBLIC_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-public-url
|
||||||
|
- name: MERCURE_JWT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-jwt-secret
|
||||||
|
- name: STORAGE_BUCKET
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-bucket
|
||||||
|
- name: STORAGE_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-endpoint
|
||||||
|
- name: STORAGE_REGION
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-region
|
||||||
|
- name: STORAGE_USE_PATH_STYLE_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-use-path-style-endpoint
|
||||||
|
- name: STORAGE_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-key
|
||||||
|
- name: STORAGE_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-secret
|
||||||
|
lifecycle:
|
||||||
|
preStop:
|
||||||
|
exec:
|
||||||
|
command: ["/bin/sh", "-c", "/bin/sleep 1; kill -QUIT 1"]
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
failureThreshold: 40
|
||||||
|
periodSeconds: 3
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
periodSeconds: 3
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
periodSeconds: 3
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources.fixtures | nindent 16 }}
|
||||||
|
{{- end }}
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
{{- if .Values.dailyCronjobs.enabled }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: {{ include "plateforme-ebs" . }}-cronjob-notify-ms-e-1
|
||||||
|
labels:
|
||||||
|
{{- include "plateforme-ebs.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
schedule: '20 2 * * *'
|
||||||
|
jobTemplate:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rollme: {{ randAlphaNum 5 | quote }}
|
||||||
|
labels:
|
||||||
|
{{- include "plateforme-ebs.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "plateforme-ebs.serviceAccountName" . }}
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}-cronjob-notify-ms-e-1
|
||||||
|
image: "{{ .Values.php.image.repository }}:{{ .Values.php.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.php.image.pullPolicy }}
|
||||||
|
command: ['/bin/sh', '-c']
|
||||||
|
args: ['bin/console app:notify-platform-membership-expiration 1 --env=prod']
|
||||||
|
env:
|
||||||
|
- name: API_ENTRYPOINT_HOST
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-host
|
||||||
|
- name: JWT_PASSPHRASE
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-passphrase
|
||||||
|
- name: JWT_PUBLIC_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-public-key
|
||||||
|
- name: JWT_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-secret-key
|
||||||
|
- name: TRUSTED_HOSTS
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-trusted-hosts
|
||||||
|
- name: TRUSTED_PROXIES
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-trusted-proxies
|
||||||
|
- name: APP_ENV
|
||||||
|
value: "prod"
|
||||||
|
- name: APP_DEBUG
|
||||||
|
value: "0"
|
||||||
|
- name: APP_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-app-secret
|
||||||
|
- name: CORS_ALLOW_ORIGIN
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-cors-allow-origin
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: database-url
|
||||||
|
- name: MERCURE_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-url
|
||||||
|
- name: MERCURE_PUBLIC_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-public-url
|
||||||
|
- name: MERCURE_JWT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-jwt-secret
|
||||||
|
- name: STORAGE_BUCKET
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-bucket
|
||||||
|
- name: STORAGE_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-endpoint
|
||||||
|
- name: STORAGE_REGION
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-region
|
||||||
|
- name: STORAGE_USE_PATH_STYLE_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-use-path-style-endpoint
|
||||||
|
- name: STORAGE_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-key
|
||||||
|
- name: STORAGE_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-secret
|
||||||
|
lifecycle:
|
||||||
|
preStop:
|
||||||
|
exec:
|
||||||
|
command: ["/bin/sh", "-c", "/bin/sleep 1; kill -QUIT 1"]
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
failureThreshold: 40
|
||||||
|
periodSeconds: 3
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
periodSeconds: 3
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
periodSeconds: 3
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources.fixtures | nindent 16 }}
|
||||||
|
{{- end }}
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
{{- if .Values.dailyCronjobs.enabled }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: {{ include "plateforme-ebs" . }}-cronjob-notify-ms-e-7
|
||||||
|
labels:
|
||||||
|
{{- include "plateforme-ebs.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
schedule: '10 21 * * *'
|
||||||
|
jobTemplate:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rollme: {{ randAlphaNum 5 | quote }}
|
||||||
|
labels:
|
||||||
|
{{- include "plateforme-ebs.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "plateforme-ebs.serviceAccountName" . }}
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}-cronjob-notify-ms-e-7
|
||||||
|
image: "{{ .Values.php.image.repository }}:{{ .Values.php.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.php.image.pullPolicy }}
|
||||||
|
command: ['/bin/sh', '-c']
|
||||||
|
args: ['bin/console app:notify-platform-membership-expiration 7 --env=prod']
|
||||||
|
env:
|
||||||
|
- name: API_ENTRYPOINT_HOST
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-host
|
||||||
|
- name: JWT_PASSPHRASE
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-passphrase
|
||||||
|
- name: JWT_PUBLIC_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-public-key
|
||||||
|
- name: JWT_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-jwt-secret-key
|
||||||
|
- name: TRUSTED_HOSTS
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-trusted-hosts
|
||||||
|
- name: TRUSTED_PROXIES
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-trusted-proxies
|
||||||
|
- name: APP_ENV
|
||||||
|
value: "prod"
|
||||||
|
- name: APP_DEBUG
|
||||||
|
value: "0"
|
||||||
|
- name: APP_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-app-secret
|
||||||
|
- name: CORS_ALLOW_ORIGIN
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-cors-allow-origin
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: database-url
|
||||||
|
- name: MERCURE_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-url
|
||||||
|
- name: MERCURE_PUBLIC_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-public-url
|
||||||
|
- name: MERCURE_JWT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: mercure-jwt-secret
|
||||||
|
- name: STORAGE_BUCKET
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-bucket
|
||||||
|
- name: STORAGE_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-endpoint
|
||||||
|
- name: STORAGE_REGION
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-region
|
||||||
|
- name: STORAGE_USE_PATH_STYLE_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-use-path-style-endpoint
|
||||||
|
- name: STORAGE_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-key
|
||||||
|
- name: STORAGE_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "plateforme-ebs" . }}
|
||||||
|
key: php-storage-secret
|
||||||
|
lifecycle:
|
||||||
|
preStop:
|
||||||
|
exec:
|
||||||
|
command: ["/bin/sh", "-c", "/bin/sleep 1; kill -QUIT 1"]
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
failureThreshold: 40
|
||||||
|
periodSeconds: 3
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
periodSeconds: 3
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- docker-healthcheck
|
||||||
|
periodSeconds: 3
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources.fixtures | nindent 16 }}
|
||||||
|
{{- end }}
|
||||||
99
src/Command/EndPlatformMembershipCommand.php
Normal file
99
src/Command/EndPlatformMembershipCommand.php
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Doctrine\Manager\UserManager;
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Enum\OfferType;
|
||||||
|
use App\Mailer\AppMailer;
|
||||||
|
use App\Mailer\Email\Command\EndPlatformMembershipMail;
|
||||||
|
use App\Notifier\SmsNotifier;
|
||||||
|
use App\Notifier\SmsNotifierTrait;
|
||||||
|
use App\Repository\ConfigurationRepository;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
#[AsCommand(name: self::CMD, description: self::DESCRIPTION)]
|
||||||
|
class EndPlatformMembershipCommand extends Command
|
||||||
|
{
|
||||||
|
use CommandTrait;
|
||||||
|
use SmsNotifierTrait;
|
||||||
|
|
||||||
|
public const CMD = 'app:end-platform-membership';
|
||||||
|
public const DESCRIPTION = 'Check overdue platform membership and set user as unpaid';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
|
#[Autowire('%kernel.environment%')]
|
||||||
|
private readonly string $environment,
|
||||||
|
private readonly AppMailer $appMailer,
|
||||||
|
private readonly ConfigurationRepository $configurationRepository,
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
private readonly SmsNotifier $notifier,
|
||||||
|
#[Autowire('%brand%')]
|
||||||
|
private readonly string $brand,
|
||||||
|
private readonly UserManager $userManager,
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->configureCommand(self::DESCRIPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$configuration = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
||||||
|
if (!$configuration->getPaidMembership()) {
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
$platform = $configuration->getPlatformName();
|
||||||
|
$io->title(self::DESCRIPTION.' ('.$this->environment.' env)');
|
||||||
|
$this->memoryReport($io);
|
||||||
|
|
||||||
|
$io->section('Getting concerned membership...');
|
||||||
|
$query = $this->userRepository->getExpiredMembership();
|
||||||
|
|
||||||
|
$io->section('Processing user updates...');
|
||||||
|
$count = 0;
|
||||||
|
/** @var User $user */
|
||||||
|
foreach ($query->toIterable() as $user) {
|
||||||
|
if ($user->getPlatformOffer()?->getType() === OfferType::ONESHOT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->comment(\sprintf(' > ending platform membership expiration for user %s (%s)',
|
||||||
|
$user->getDisplayName(),
|
||||||
|
$user->getEmail(),
|
||||||
|
));
|
||||||
|
|
||||||
|
$user->setMembershipPaid(false)
|
||||||
|
->setEndAt(null)
|
||||||
|
->setPayedAt(null)
|
||||||
|
->setStartAt(null)
|
||||||
|
->setPlatformOffer(null);
|
||||||
|
|
||||||
|
$this->userManager->save($user, true);
|
||||||
|
|
||||||
|
$this->appMailer->send(EndPlatformMembershipMail::class, compact('user', 'platform'));
|
||||||
|
$this->sendSms($user, EndPlatformMembershipMail::class, ['%platform%' => $platform]);
|
||||||
|
++$count;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->note(\sprintf(' > %d update(s) done.', $count));
|
||||||
|
$this->memoryReport($io);
|
||||||
|
$this->done($io);
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/Command/NotifyPlatformMembershipExpirationCommand.php
Normal file
95
src/Command/NotifyPlatformMembershipExpirationCommand.php
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Enum\OfferType;
|
||||||
|
use App\Mailer\AppMailer;
|
||||||
|
use App\Mailer\Email\Command\NotifyPlatformMembershipExpirationMail;
|
||||||
|
use App\Notifier\SmsNotifier;
|
||||||
|
use App\Notifier\SmsNotifierTrait;
|
||||||
|
use App\Repository\ConfigurationRepository;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
#[AsCommand(name: self::CMD, description: self::DESCRIPTION)]
|
||||||
|
class NotifyPlatformMembershipExpirationCommand extends Command
|
||||||
|
{
|
||||||
|
use CommandTrait;
|
||||||
|
use SmsNotifierTrait;
|
||||||
|
|
||||||
|
public const CMD = 'app:notify-platform-membership-expiration';
|
||||||
|
public const DESCRIPTION = 'Notify expiring platform membership.';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
private readonly AppMailer $appMailer,
|
||||||
|
private readonly SmsNotifier $notifier,
|
||||||
|
#[Autowire('%kernel.environment%')]
|
||||||
|
private readonly string $environment,
|
||||||
|
#[Autowire('%brand%')]
|
||||||
|
private readonly string $brand,
|
||||||
|
private readonly ConfigurationRepository $configurationRepository,
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->configureCommand(self::DESCRIPTION);
|
||||||
|
$this->addArgument('days', InputArgument::REQUIRED, 'Number of days from tomorrow (1 = notify members expiring tomorrow)');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$configuration = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
||||||
|
if (!$configuration->getPaidMembership()) {
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
$platform = $configuration->getPlatformName();
|
||||||
|
$io->title(self::DESCRIPTION.' ('.$this->environment.' env)');
|
||||||
|
$this->memoryReport($io);
|
||||||
|
|
||||||
|
/** @var string $days */
|
||||||
|
$days = $input->getArgument('days');
|
||||||
|
$days = max(1, (int) $days);
|
||||||
|
|
||||||
|
$io->section(\sprintf('Getting platform membership expiring in %d days...', $days));
|
||||||
|
$query = $this->userRepository->getExpiring($days);
|
||||||
|
$io->section('Sending notifications...');
|
||||||
|
$count = 0;
|
||||||
|
/** @var User $user */
|
||||||
|
foreach ($query->toIterable() as $user) {
|
||||||
|
if ($user->getPlatformOffer()?->getType() === OfferType::ONESHOT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->comment(\sprintf(' > notifying platform membership expiration for user %s (%s)',
|
||||||
|
$user->getDisplayName(),
|
||||||
|
$user->getEmail(),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->appMailer->send(NotifyPlatformMembershipExpirationMail::class, compact('user', 'days', 'platform'));
|
||||||
|
$this->sendSms($user, NotifyPlatformMembershipExpirationMail::class, ['%days%' => $days, '%platform%' => $platform]);
|
||||||
|
++$count;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->note(\sprintf(' > %d notification(s) sent.', $count));
|
||||||
|
|
||||||
|
$this->memoryReport($io);
|
||||||
|
$this->done($io);
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@ use App\Flysystem\MediaManager;
|
||||||
use App\Helper\CsvExporter;
|
use App\Helper\CsvExporter;
|
||||||
use App\Mailer\AppMailer;
|
use App\Mailer\AppMailer;
|
||||||
use App\Mailer\Email\Admin\PromoteToAdmin\PromoteToAdminEmail;
|
use App\Mailer\Email\Admin\PromoteToAdmin\PromoteToAdminEmail;
|
||||||
|
use App\Repository\ConfigurationRepository;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
|
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
|
||||||
|
|
@ -37,10 +38,12 @@ use EasyCorp\Bundle\EasyAdminBundle\Factory\FormFactory;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Filter\DateTimeFilter;
|
use EasyCorp\Bundle\EasyAdminBundle\Filter\DateTimeFilter;
|
||||||
|
|
@ -89,6 +92,7 @@ abstract class AbstractUserCrudController extends AbstractCrudController impleme
|
||||||
#[Autowire('%user_base_path%')]
|
#[Autowire('%user_base_path%')]
|
||||||
private readonly string $userBasePath,
|
private readonly string $userBasePath,
|
||||||
AppMailer $mailer,
|
AppMailer $mailer,
|
||||||
|
private readonly ConfigurationRepository $configurationRepository,
|
||||||
) {
|
) {
|
||||||
$this->mailer = $mailer;
|
$this->mailer = $mailer;
|
||||||
}
|
}
|
||||||
|
|
@ -355,6 +359,20 @@ abstract class AbstractUserCrudController extends AbstractCrudController impleme
|
||||||
$vacationModeField = BooleanField::new('vacationMode');
|
$vacationModeField = BooleanField::new('vacationMode');
|
||||||
$addressField = AssociationField::new('address');
|
$addressField = AssociationField::new('address');
|
||||||
$groupsCountField = AssociationField::new('userGroups')->setLabel('Groups number');
|
$groupsCountField = AssociationField::new('userGroups')->setLabel('Groups number');
|
||||||
|
$membershipPaidField = BooleanField::new('membershipPaid');
|
||||||
|
$startAt = DateField::new('startAt');
|
||||||
|
$endAt = DateField::new('endAt');
|
||||||
|
$expiresInField = IntegerField::new('expiresIn')
|
||||||
|
->formatValue(function ($value) {
|
||||||
|
return $value !== null ? $this->translator->trans($this->getI18nPrefix().'.expires_in.formatted_value', ['%days%' => $value], 'admin') : '';
|
||||||
|
})
|
||||||
|
->setFormTypeOptions([
|
||||||
|
'attr' => ['readonly' => 'readonly'],
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
$payedAt = DateTimeField::new('payedAt');
|
||||||
|
$offerField = AssociationField::new('platformOffer');
|
||||||
|
|
||||||
return compact(
|
return compact(
|
||||||
'idField',
|
'idField',
|
||||||
|
|
@ -378,6 +396,12 @@ abstract class AbstractUserCrudController extends AbstractCrudController impleme
|
||||||
'vacationModeField',
|
'vacationModeField',
|
||||||
'addressField',
|
'addressField',
|
||||||
'groupsCountField',
|
'groupsCountField',
|
||||||
|
'membershipPaidField',
|
||||||
|
'startAt',
|
||||||
|
'endAt',
|
||||||
|
'expiresInField',
|
||||||
|
'payedAt',
|
||||||
|
'offerField',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -445,4 +469,9 @@ abstract class AbstractUserCrudController extends AbstractCrudController impleme
|
||||||
|
|
||||||
return $builder;
|
return $builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function platformRequiresGlobalPayment(): bool
|
||||||
|
{
|
||||||
|
return $this->configurationRepository->getInstanceConfigurationOrCreate()->getPaidMembership();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,16 +48,27 @@ final class UserCrudController extends AbstractUserCrudController
|
||||||
'vacationModeField' => $vacationModeField,
|
'vacationModeField' => $vacationModeField,
|
||||||
'addressField' => $addressField,
|
'addressField' => $addressField,
|
||||||
'groupsCountField' => $groupsCountField,
|
'groupsCountField' => $groupsCountField,
|
||||||
|
'membershipPaidField' => $membershipPaidField,
|
||||||
|
'startAt' => $startAt,
|
||||||
|
'endAt' => $endAt,
|
||||||
|
'expiresInField' => $expiresInField,
|
||||||
|
'payedAt' => $payedAt,
|
||||||
|
'offerField' => $offerField,
|
||||||
] = $this->getFields($pageName);
|
] = $this->getFields($pageName);
|
||||||
|
|
||||||
if ($pageName === Crud::PAGE_INDEX) {
|
if ($pageName === Crud::PAGE_INDEX) {
|
||||||
return [$emailField, $firstNameField, $lastNameField, $enabledField, $emailConfirmedField, $avatarField, $createdAt, $updatedAt, $loginAt, $groupsCountField];
|
$listFields = [$emailField, $firstNameField, $lastNameField, $enabledField, $emailConfirmedField, $avatarField, $createdAt, $updatedAt, $loginAt, $groupsCountField];
|
||||||
|
if ($this->platformRequiresGlobalPayment()) {
|
||||||
|
$listFields[] = $membershipPaidField;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $listFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
$panels = $this->getPanels();
|
$panels = $this->getPanels();
|
||||||
|
|
||||||
if ($pageName === Crud::PAGE_NEW || $pageName === Crud::PAGE_EDIT) {
|
if ($pageName === Crud::PAGE_NEW || $pageName === Crud::PAGE_EDIT) {
|
||||||
return [
|
$editFields = [
|
||||||
$panels['information'],
|
$panels['information'],
|
||||||
$emailField,
|
$emailField,
|
||||||
$firstNameField,
|
$firstNameField,
|
||||||
|
|
@ -74,9 +85,21 @@ final class UserCrudController extends AbstractUserCrudController
|
||||||
$enabledField,
|
$enabledField,
|
||||||
$emailConfirmedField,
|
$emailConfirmedField,
|
||||||
];
|
];
|
||||||
|
if ($this->platformRequiresGlobalPayment()) {
|
||||||
|
$editFields = array_merge($editFields, [
|
||||||
|
$panels['payment_information'],
|
||||||
|
$membershipPaidField,
|
||||||
|
$offerField,
|
||||||
|
$startAt,
|
||||||
|
$endAt,
|
||||||
|
$payedAt,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $editFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
$showFields = [
|
||||||
$panels['information'],
|
$panels['information'],
|
||||||
$emailField,
|
$emailField,
|
||||||
$firstNameField,
|
$firstNameField,
|
||||||
|
|
@ -97,5 +120,17 @@ final class UserCrudController extends AbstractUserCrudController
|
||||||
$updatedAt,
|
$updatedAt,
|
||||||
$loginAt,
|
$loginAt,
|
||||||
];
|
];
|
||||||
|
if ($this->platformRequiresGlobalPayment()) {
|
||||||
|
$showFields = array_merge($showFields, [
|
||||||
|
$panels['payment_information'],
|
||||||
|
$membershipPaidField,
|
||||||
|
$startAt,
|
||||||
|
$endAt,
|
||||||
|
$payedAt,
|
||||||
|
$expiresInField,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $showFields;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Routing\Requirement\Requirement;
|
use Symfony\Component\Routing\Requirement\Requirement;
|
||||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ namespace App\Controller\Payment\PlatformMembership;
|
||||||
|
|
||||||
use App\Controller\FlashTrait;
|
use App\Controller\FlashTrait;
|
||||||
use App\Controller\i18nTrait;
|
use App\Controller\i18nTrait;
|
||||||
use App\Doctrine\Manager\UserManager;
|
|
||||||
use App\Entity\PaymentToken;
|
use App\Entity\PaymentToken;
|
||||||
use App\Entity\PlatformOffer;
|
use App\Entity\PlatformOffer;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use Carbon\CarbonImmutable;
|
use App\Message\Command\Payment\PlatformMembershipPaidCommand;
|
||||||
|
use App\MessageBus\CommandBusInterface;
|
||||||
use Payum\Core\Payum;
|
use Payum\Core\Payum;
|
||||||
use Payum\Core\Request\GetHumanStatus;
|
use Payum\Core\Request\GetHumanStatus;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
@ -19,7 +19,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Routing\Requirement\Requirement;
|
use Symfony\Component\Routing\Requirement\Requirement;
|
||||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
@ -33,6 +33,14 @@ final class DoneAction extends AbstractController
|
||||||
|
|
||||||
public const ROUTE_NAME = 'app_platform_payment_done';
|
public const ROUTE_NAME = 'app_platform_payment_done';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly CommandBusInterface $commandBus,
|
||||||
|
private readonly Payum $payum,
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://github.com/Payum/Payum/blob/master/docs/symfony/get-it-started.md#payment-is-done
|
* @see https://github.com/Payum/Payum/blob/master/docs/symfony/get-it-started.md#payment-is-done
|
||||||
*/
|
*/
|
||||||
|
|
@ -41,41 +49,37 @@ final class DoneAction extends AbstractController
|
||||||
name: self::ROUTE_NAME,
|
name: self::ROUTE_NAME,
|
||||||
requirements: ['id' => Requirement::UUID_V6],
|
requirements: ['id' => Requirement::UUID_V6],
|
||||||
)]
|
)]
|
||||||
public function __invoke(Request $request, #[MapEntity(expr: 'repository.findOneActive(id)')] PlatformOffer $platformOffer, #[CurrentUser] User $user, Payum $payum, TranslatorInterface $translator, UserManager $userManager, LoggerInterface $logger): Response
|
public function __invoke(Request $request, #[MapEntity(expr: 'repository.findOneActive(id)')] PlatformOffer $platformOffer, #[CurrentUser] User $user): Response
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
/** @var PaymentToken $token */
|
/** @var PaymentToken $token */
|
||||||
$token = $payum->getHttpRequestVerifier()->verify($request);
|
$token = $this->payum->getHttpRequestVerifier()->verify($request);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$logger->error($e->getMessage());
|
$this->logger->error($e->getMessage());
|
||||||
throw new UnprocessableEntityHttpException('Cannot verify Payum token.');
|
throw new UnprocessableEntityHttpException('Cannot verify Payum token.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$gateway = $payum->getGateway($token->getGatewayName());
|
/** @var GetHumanStatus $status */
|
||||||
$status = new GetHumanStatus($token);
|
$status = $this->commandBus->dispatch(new PlatformMembershipPaidCommand($platformOffer->getId(), $user->getId(), $token));
|
||||||
$gateway->execute($status);
|
|
||||||
|
|
||||||
// Not captured
|
// Not captured
|
||||||
if (!$status->isCaptured()) {
|
if (!$status->isCaptured()) {
|
||||||
$this->addFlashWarning($translator->trans($this->getI18nPrefix().'.status.'.$status->getValue()));
|
$this->addFlashWarning($this->translator->trans($this->getI18nPrefix().'.status.'.$status->getValue()));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_user_my_account');
|
||||||
}
|
}
|
||||||
|
|
||||||
$user
|
$this->addFlashSuccess($this->translator->trans($this->getI18nPrefix().'.flash.success', [
|
||||||
->setMembershipPaid(true)
|
|
||||||
->setStartAt(CarbonImmutable::today())
|
|
||||||
->setPayedAt(CarbonImmutable::now())
|
|
||||||
;
|
|
||||||
if (($offerType = $platformOffer->getType())->isRecurring()) {
|
|
||||||
$user->setEndAt(new CarbonImmutable($offerType->getEndAtInterval()));
|
|
||||||
}
|
|
||||||
|
|
||||||
$userManager->save($user, true);
|
|
||||||
|
|
||||||
$this->addFlashSuccess($translator->trans($this->getI18nPrefix().'.flash.success', [
|
|
||||||
'%platform%' => $platformOffer->getConfiguration()?->getPlatformName()],
|
'%platform%' => $platformOffer->getConfiguration()?->getPlatformName()],
|
||||||
));
|
));
|
||||||
|
|
||||||
$request->getSession()->remove('payment_in_progress');
|
$request->getSession()->remove('payment_in_progress');
|
||||||
|
|
||||||
|
$group = $user->getMyGroupsAsInvited()->first();
|
||||||
|
if ($group !== false) {
|
||||||
|
return $this->redirectToRoute('app_group_show_logged', $group->getRoutingParameters());
|
||||||
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_user_my_account');
|
return $this->redirectToRoute('app_user_my_account');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ use App\Message\Query\Security\GetUserByTokenQuery;
|
||||||
use App\MessageBus\CommandBus;
|
use App\MessageBus\CommandBus;
|
||||||
use App\MessageBus\QueryBus;
|
use App\MessageBus\QueryBus;
|
||||||
use App\MessageHandler\Command\Security\AccountCreateStep1CommandHandler;
|
use App\MessageHandler\Command\Security\AccountCreateStep1CommandHandler;
|
||||||
|
use App\Repository\ConfigurationRepository;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
@ -41,6 +42,7 @@ final class AccountCreateController extends AbstractController
|
||||||
private readonly QueryBus $queryBus,
|
private readonly QueryBus $queryBus,
|
||||||
private readonly CommandBus $commandBus,
|
private readonly CommandBus $commandBus,
|
||||||
private readonly Security $security,
|
private readonly Security $security,
|
||||||
|
private readonly ConfigurationRepository $configurationRepository,
|
||||||
) {
|
) {
|
||||||
$this->i18nPrefix = $this->getI18nPrefix();
|
$this->i18nPrefix = $this->getI18nPrefix();
|
||||||
}
|
}
|
||||||
|
|
@ -97,6 +99,7 @@ final class AccountCreateController extends AbstractController
|
||||||
return $this->redirectToRoute('app_login');
|
return $this->redirectToRoute('app_login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$configuration = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
||||||
// nominal case: user found and token not expired
|
// nominal case: user found and token not expired
|
||||||
$form = $this->createForm(AccountCreateStep2FormType::class, $user->setStep2Defaults())->handleRequest($request);
|
$form = $this->createForm(AccountCreateStep2FormType::class, $user->setStep2Defaults())->handleRequest($request);
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|
@ -110,13 +113,26 @@ final class AccountCreateController extends AbstractController
|
||||||
// page group.
|
// page group.
|
||||||
$group = $user->getMyGroupsAsInvited()->first();
|
$group = $user->getMyGroupsAsInvited()->first();
|
||||||
if ($group !== false) {
|
if ($group !== false) {
|
||||||
$this->addFlashSuccess($this->i18nPrefix.'.step2.with_invitation.flash.success');
|
// If platform needs payment, redirect to payment
|
||||||
|
if ($configuration->getPaidMembership()) {
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.with_invitation.global_paid_membership.flash.success';
|
||||||
|
$this->addFlashSuccess($successMessage);
|
||||||
|
|
||||||
|
return $this->redirectToRoute('redirect_to_payment');
|
||||||
|
}
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.with_invitation.flash.success';
|
||||||
|
$this->addFlashSuccess($successMessage);
|
||||||
|
|
||||||
return $this->redirectToRoute('app_group_show_logged', $group->getRoutingParameters());
|
return $this->redirectToRoute('app_group_show_logged', $group->getRoutingParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($configuration->getPaidMembership()) {
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.global_paid_membership.flash.success';
|
||||||
|
} else {
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.flash.success';
|
||||||
|
}
|
||||||
// otherwise go to the address form
|
// otherwise go to the address form
|
||||||
$this->addFlashSuccess($this->i18nPrefix.'.step2.flash.success');
|
$this->addFlashSuccess($successMessage);
|
||||||
|
|
||||||
return $this->redirectToRoute(MyAccountAction::ROUTE);
|
return $this->redirectToRoute(MyAccountAction::ROUTE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ final class MembershipPaidListener
|
||||||
|
|
||||||
public function onKernelException(ExceptionEvent $event): void
|
public function onKernelException(ExceptionEvent $event): void
|
||||||
{
|
{
|
||||||
/** @var User $user */
|
|
||||||
$user = $this->security->getUser();
|
$user = $this->security->getUser();
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$config = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
$config = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
||||||
$session = $event->getRequest()->getSession();
|
$session = $event->getRequest()->getSession();
|
||||||
/** @var bool $isPaymentInProgress */
|
/** @var bool $isPaymentInProgress */
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ trait FieldTrait
|
||||||
return [
|
return [
|
||||||
'information' => FormField::addPanel('panel.information', 'fas fa-info-circle'),
|
'information' => FormField::addPanel('panel.information', 'fas fa-info-circle'),
|
||||||
'tech_information' => FormField::addPanel('panel.tech_information', 'fas fa-history'),
|
'tech_information' => FormField::addPanel('panel.tech_information', 'fas fa-history'),
|
||||||
|
'payment_information' => FormField::addPanel('panel.payment_information', 'fas fa-dollar-sign'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ use App\Form\Type\User\ChangeLoginFormType;
|
||||||
use App\Form\Type\User\ChangePasswordFormType;
|
use App\Form\Type\User\ChangePasswordFormType;
|
||||||
use App\Form\Type\User\EditProfileFormType;
|
use App\Form\Type\User\EditProfileFormType;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
|
use App\Validator\Constraints\User\MembershipPaid;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\DBAL\Types\Types;
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
|
@ -26,6 +28,7 @@ use libphonenumber\PhoneNumberUtil;
|
||||||
use Misd\PhoneNumberBundle\Validator\Constraints\PhoneNumber as AssertPhoneNumber;
|
use Misd\PhoneNumberBundle\Validator\Constraints\PhoneNumber as AssertPhoneNumber;
|
||||||
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
|
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
use Symfony\Component\Security\Core\User\EquatableInterface;
|
||||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
|
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
|
||||||
|
|
@ -42,7 +45,8 @@ use function Symfony\Component\String\u;
|
||||||
#[ORM\Table(name: '`user`')] // we also need escaping here
|
#[ORM\Table(name: '`user`')] // we also need escaping here
|
||||||
#[ORM\EntityListeners([UserListener::class])]
|
#[ORM\EntityListeners([UserListener::class])]
|
||||||
#[UniqueEntity('email', groups: [AccountCreateStep1FormType::class, ChangeLoginFormType::class, 'Default'])]
|
#[UniqueEntity('email', groups: [AccountCreateStep1FormType::class, ChangeLoginFormType::class, 'Default'])]
|
||||||
class User implements UserInterface, PasswordAuthenticatedUserInterface, ImageInterface
|
#[MembershipPaid]
|
||||||
|
class User implements UserInterface, PasswordAuthenticatedUserInterface, ImageInterface, EquatableInterface
|
||||||
{
|
{
|
||||||
use UserConfirmationTrait;
|
use UserConfirmationTrait;
|
||||||
use UserLostPasswordTrait;
|
use UserLostPasswordTrait;
|
||||||
|
|
@ -272,6 +276,10 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, ImageIn
|
||||||
#[ORM\Column(type: 'boolean', nullable: false)]
|
#[ORM\Column(type: 'boolean', nullable: false)]
|
||||||
private bool $membershipPaid = false;
|
private bool $membershipPaid = false;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne(targetEntity: PlatformOffer::class)]
|
||||||
|
#[ORM\JoinColumn(referencedColumnName: 'id', onDelete: 'SET NULL')]
|
||||||
|
private ?PlatformOffer $platformOffer = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starting date of a paying membership. The starting date of a free membership
|
* Starting date of a paying membership. The starting date of a free membership
|
||||||
* is stored in the creation date.
|
* is stored in the creation date.
|
||||||
|
|
@ -992,4 +1000,35 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, ImageIn
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function expiresIn(): ?int
|
||||||
|
{
|
||||||
|
$today = Carbon::today();
|
||||||
|
if ($this->endAt === null || $this->endAt < $today) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$endAt = new Carbon($this->endAt);
|
||||||
|
|
||||||
|
return $today->diffInDays($endAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPlatformOffer(): ?PlatformOffer
|
||||||
|
{
|
||||||
|
return $this->platformOffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPlatformOffer(?PlatformOffer $platformOffer): void
|
||||||
|
{
|
||||||
|
$this->platformOffer = $platformOffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEqualTo(UserInterface $user): bool
|
||||||
|
{
|
||||||
|
if (!$user instanceof self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->email === $user->getUserIdentifier() && $this->password === $user->getPassword();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
src/Mailer/Email/Command/EndPlatformMembershipMail.php
Normal file
50
src/Mailer/Email/Command/EndPlatformMembershipMail.php
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Mailer\Email\Command;
|
||||||
|
|
||||||
|
use App\Controller\i18nTrait;
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Mailer\AppMailer;
|
||||||
|
use App\Mailer\Email\EmailInterface;
|
||||||
|
use App\Mailer\Email\EmailTrait;
|
||||||
|
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Symfony\Component\Mime\Email;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Webmozart\Assert\Assert;
|
||||||
|
|
||||||
|
class EndPlatformMembershipMail implements EmailInterface
|
||||||
|
{
|
||||||
|
use EmailTrait;
|
||||||
|
use i18nTrait;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
#[Autowire('%brand%')]
|
||||||
|
private readonly string $brand,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $context
|
||||||
|
*/
|
||||||
|
public function getEmail(array $context): TemplatedEmail
|
||||||
|
{
|
||||||
|
/** @var ?User $user */
|
||||||
|
$user = $context['user'] ?? null;
|
||||||
|
Assert::isInstanceOf($user, User::class);
|
||||||
|
|
||||||
|
return (new TemplatedEmail())
|
||||||
|
->to($user->getEmail())
|
||||||
|
->priority(Email::PRIORITY_HIGH)
|
||||||
|
->subject($this->translator->trans($this->getI18nPrefix().'.subject', [
|
||||||
|
'%brand%' => $this->brand,
|
||||||
|
'%platform%' => $context['platform'],
|
||||||
|
], AppMailer::TR_DOMAIN))
|
||||||
|
->htmlTemplate('email/command/end_platform_membership.html.twig')
|
||||||
|
->context($context)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Mailer\Email\Command;
|
||||||
|
|
||||||
|
use App\Controller\i18nTrait;
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Mailer\AppMailer;
|
||||||
|
use App\Mailer\Email\EmailInterface;
|
||||||
|
use App\Mailer\Email\EmailTrait;
|
||||||
|
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Symfony\Component\Mime\Email;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Webmozart\Assert\Assert;
|
||||||
|
|
||||||
|
class NotifyPlatformMembershipExpirationMail implements EmailInterface
|
||||||
|
{
|
||||||
|
use EmailTrait;
|
||||||
|
use i18nTrait;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
#[Autowire('%brand%')]
|
||||||
|
private readonly string $brand,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $context
|
||||||
|
*/
|
||||||
|
public function getEmail(array $context): TemplatedEmail
|
||||||
|
{
|
||||||
|
/** @var ?User $user */
|
||||||
|
$user = $context['user'] ?? null;
|
||||||
|
Assert::isInstanceOf($user, User::class);
|
||||||
|
|
||||||
|
return (new TemplatedEmail())
|
||||||
|
->to($user->getEmail())
|
||||||
|
->priority(Email::PRIORITY_HIGH)
|
||||||
|
->subject($this->translator->trans($this->getI18nPrefix().'.subject', [
|
||||||
|
'%brand%' => $this->brand,
|
||||||
|
'%days%' => $context['days'],
|
||||||
|
'%platform%' => $context['platform'],
|
||||||
|
], AppMailer::TR_DOMAIN))
|
||||||
|
->htmlTemplate('email/command/notify_platform_membership_expiration.html.twig')
|
||||||
|
->context($context)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/Mailer/Email/Payment/PlatformMembershipPaidMail.php
Normal file
50
src/Mailer/Email/Payment/PlatformMembershipPaidMail.php
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Mailer\Email\Payment;
|
||||||
|
|
||||||
|
use App\Controller\i18nTrait;
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Mailer\AppMailer;
|
||||||
|
use App\Mailer\Email\EmailInterface;
|
||||||
|
use App\Mailer\Email\EmailTrait;
|
||||||
|
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Symfony\Component\Mime\Email;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Webmozart\Assert\Assert;
|
||||||
|
|
||||||
|
class PlatformMembershipPaidMail implements EmailInterface
|
||||||
|
{
|
||||||
|
use EmailTrait;
|
||||||
|
use i18nTrait;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
#[Autowire('%brand%')]
|
||||||
|
private readonly string $brand,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $context
|
||||||
|
*/
|
||||||
|
public function getEmail(array $context): TemplatedEmail
|
||||||
|
{
|
||||||
|
/** @var ?User $user */
|
||||||
|
$user = $context['user'] ?? null;
|
||||||
|
Assert::isInstanceOf($user, User::class);
|
||||||
|
|
||||||
|
return (new TemplatedEmail())
|
||||||
|
->to($user->getEmail())
|
||||||
|
->priority(Email::PRIORITY_HIGH)
|
||||||
|
->subject($this->translator->trans($this->getI18nPrefix().'.subject', [
|
||||||
|
'%brand%' => $this->brand,
|
||||||
|
'%platform%' => $context['platform'],
|
||||||
|
], AppMailer::TR_DOMAIN))
|
||||||
|
->htmlTemplate('email/payment/platform_membership_paid.html.twig')
|
||||||
|
->context($context)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Message\Command\Payment;
|
||||||
|
|
||||||
|
use App\Entity\PaymentToken;
|
||||||
|
use App\MessageHandler\Command\Payment\PlatformMembershipPaidCommandHandler;
|
||||||
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PlatformMembershipPaidCommandHandler
|
||||||
|
*/
|
||||||
|
final class PlatformMembershipPaidCommand
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public readonly Uuid $platformOfferId,
|
||||||
|
public readonly Uuid $userId,
|
||||||
|
public readonly PaymentToken $paymentToken,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\MessageHandler\Command\Payment;
|
||||||
|
|
||||||
|
use App\Doctrine\Manager\UserManager;
|
||||||
|
use App\Mailer\AppMailer;
|
||||||
|
use App\Mailer\Email\Payment\PlatformMembershipPaidMail;
|
||||||
|
use App\Message\Command\Payment\PlatformMembershipPaidCommand;
|
||||||
|
use App\Repository\ConfigurationRepository;
|
||||||
|
use App\Repository\PlatformOfferRepository;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
use Payum\Core\Payum;
|
||||||
|
use Payum\Core\Request\GetHumanStatus;
|
||||||
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||||
|
|
||||||
|
#[AsMessageHandler]
|
||||||
|
final class PlatformMembershipPaidCommandHandler
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly PlatformOfferRepository $platformOfferRepository,
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
|
private readonly UserManager $userManager,
|
||||||
|
private readonly Payum $payum,
|
||||||
|
private readonly AppMailer $mailer,
|
||||||
|
private readonly ConfigurationRepository $configurationRepository,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(PlatformMembershipPaidCommand $message): GetHumanStatus
|
||||||
|
{
|
||||||
|
$platformOffer = $this->platformOfferRepository->get($message->platformOfferId);
|
||||||
|
$user = $this->userRepository->get($message->userId);
|
||||||
|
|
||||||
|
$gateway = $this->payum->getGateway($message->paymentToken->getGatewayName());
|
||||||
|
$status = new GetHumanStatus($message->paymentToken);
|
||||||
|
$gateway->execute($status);
|
||||||
|
|
||||||
|
// Not captured
|
||||||
|
if (!$status->isCaptured()) {
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user
|
||||||
|
->setMembershipPaid(true)
|
||||||
|
->setStartAt(CarbonImmutable::today())
|
||||||
|
->setPayedAt(CarbonImmutable::now())
|
||||||
|
->setPlatformOffer($platformOffer)
|
||||||
|
;
|
||||||
|
if (($offerType = $platformOffer->getType())->isRecurring()) {
|
||||||
|
$user->setEndAt(new CarbonImmutable($offerType->getEndAtInterval()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->userManager->save($user, true);
|
||||||
|
|
||||||
|
// payment was captured and membership is saved so invalidate the token
|
||||||
|
$this->payum->getHttpRequestVerifier()->invalidate($message->paymentToken);
|
||||||
|
|
||||||
|
// send confirmation email
|
||||||
|
$configuration = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
||||||
|
$platform = $configuration->getPlatformName();
|
||||||
|
$this->mailer->send(PlatformMembershipPaidMail::class, [
|
||||||
|
'platform' => $platform,
|
||||||
|
'user' => $user,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,9 +6,11 @@ namespace App\Repository;
|
||||||
|
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Enum\User\UserType;
|
use App\Enum\User\UserType;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\ORM\NonUniqueResultException;
|
use Doctrine\ORM\NonUniqueResultException;
|
||||||
use Doctrine\ORM\NoResultException;
|
use Doctrine\ORM\NoResultException;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||||
|
|
@ -147,4 +149,32 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
|
||||||
->getQuery()
|
->getQuery()
|
||||||
->getSingleScalarResult();
|
->getSingleScalarResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getExpiredMembership(): Query
|
||||||
|
{
|
||||||
|
$today = Carbon::today();
|
||||||
|
$qb = $this
|
||||||
|
->createQueryBuilder('u')
|
||||||
|
->andWhere('u.endAt < :date')
|
||||||
|
->setParameter('date', $today->format('Y-m-d'))
|
||||||
|
;
|
||||||
|
|
||||||
|
return $qb->getQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExpiring(int $days): Query
|
||||||
|
{
|
||||||
|
$from = new \DateTimeImmutable(\sprintf('+%d days midnight', $days));
|
||||||
|
$to = $from->modify('+ 1 day'); // just add one day for the end limit
|
||||||
|
|
||||||
|
$qb = $this
|
||||||
|
->createQueryBuilder('u')
|
||||||
|
->andWhere('u.endAt >= :from')
|
||||||
|
->andWhere('u.endAt < :to')
|
||||||
|
->setParameter('from', $from->format('Y-m-d'))
|
||||||
|
->setParameter('to', $to->format('Y-m-d'))
|
||||||
|
;
|
||||||
|
|
||||||
|
return $qb->getQuery();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use App\Repository\MenuItemRepository;
|
||||||
use App\Repository\MenuRepository;
|
use App\Repository\MenuRepository;
|
||||||
use App\Repository\MessageRepository;
|
use App\Repository\MessageRepository;
|
||||||
use App\Repository\PaymentRepository;
|
use App\Repository\PaymentRepository;
|
||||||
|
use App\Repository\PlatformOfferRepository;
|
||||||
use App\Repository\ProductAvailabilityRepository;
|
use App\Repository\ProductAvailabilityRepository;
|
||||||
use App\Repository\ProductRepository;
|
use App\Repository\ProductRepository;
|
||||||
use App\Repository\ServiceRequestRepository;
|
use App\Repository\ServiceRequestRepository;
|
||||||
|
|
@ -113,4 +114,9 @@ trait ContainerRepositoryTrait
|
||||||
{
|
{
|
||||||
return self::getContainer()->get(ServiceRequestRepository::class);
|
return self::getContainer()->get(ServiceRequestRepository::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPlatformOfferRepository(): PlatformOfferRepository
|
||||||
|
{
|
||||||
|
return self::getContainer()->get(PlatformOfferRepository::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/Validator/Constraints/User/MembershipPaid.php
Normal file
18
src/Validator/Constraints/User/MembershipPaid.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints\User;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||||
|
class MembershipPaid extends Constraint
|
||||||
|
{
|
||||||
|
public string $message = 'validator.user.membership_paid';
|
||||||
|
|
||||||
|
public function getTargets(): string
|
||||||
|
{
|
||||||
|
return self::CLASS_CONSTRAINT;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/Validator/Constraints/User/MembershipPaidValidator.php
Normal file
58
src/Validator/Constraints/User/MembershipPaidValidator.php
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints\User;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Enum\OfferType;
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
|
class MembershipPaidValidator extends ConstraintValidator
|
||||||
|
{
|
||||||
|
public function validate(mixed $value, Constraint $constraint): void
|
||||||
|
{
|
||||||
|
if (!$constraint instanceof MembershipPaid) {
|
||||||
|
throw new UnexpectedTypeException($constraint, MembershipPaid::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$value instanceof User) {
|
||||||
|
throw new UnexpectedValueException($value, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$value->isMembershipPaid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$platformOffer = $value->getPlatformOffer();
|
||||||
|
if (null === $platformOffer) {
|
||||||
|
$this->context->buildViolation($constraint->message)
|
||||||
|
->atPath('platformOffer')
|
||||||
|
->addViolation();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (null === $value->getStartAt()) {
|
||||||
|
$this->context->buildViolation($constraint->message)
|
||||||
|
->atPath('startAt')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
match ($platformOffer->getType()) {
|
||||||
|
OfferType::YEARLY, OfferType::MONTHLY => $this->checkEndAt($value, $constraint),
|
||||||
|
OfferType::ONESHOT => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkEndAt(User $value, MembershipPaid $constraint): void
|
||||||
|
{
|
||||||
|
if (null === $value->getEndAt()) {
|
||||||
|
$this->context->buildViolation($constraint->message)
|
||||||
|
->atPath('endAt')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
templates/email/command/end_platform_membership.html.twig
Normal file
11
templates/email/command/end_platform_membership.html.twig
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{% trans_default_domain 'email' %}
|
||||||
|
|
||||||
|
{% set i18n_prefix = _self|i18n_prefix %}
|
||||||
|
|
||||||
|
<p>{{ (i18n_prefix ~ '.h1')|trans }}</p>
|
||||||
|
|
||||||
|
<p>{{ (i18n_prefix ~ '.p1')|trans({'%endAt%': user.endAt, '%platform%': platform}) }}</p>
|
||||||
|
|
||||||
|
<a href="{{ url('app_login') }}">{{ (i18n_prefix ~ '.loginLink')|trans }}</a>
|
||||||
|
|
||||||
|
<p>{{ brand }}</p>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% trans_default_domain 'email' %}
|
||||||
|
|
||||||
|
{% set i18n_prefix = _self|i18n_prefix %}
|
||||||
|
|
||||||
|
<p>{{ (i18n_prefix ~ '.h1')|trans }}</p>
|
||||||
|
|
||||||
|
<p>{{ (i18n_prefix ~ '.p1')|trans({'%platform%': platform, '%days%': days}) }}</p>
|
||||||
|
|
||||||
|
<p>{{ brand }}</p>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% trans_default_domain 'email' %}
|
||||||
|
|
||||||
|
{% set i18n_prefix = _self|i18n_prefix %}
|
||||||
|
|
||||||
|
<p>{{ (i18n_prefix ~ '.h1')|trans }}</p>
|
||||||
|
|
||||||
|
<p>{{ (i18n_prefix ~ '.p1')|trans({'%startAt%': user.startAt, '%endAt%': user.endAt, '%platform%': platform}) }}</p>
|
||||||
|
|
||||||
|
<p>{{ brand }}</p>
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Integration\Command;
|
||||||
|
|
||||||
|
use App\Command\EndPlatformMembershipCommand;
|
||||||
|
use App\Test\ContainerRepositoryTrait;
|
||||||
|
use App\Test\ContainerTrait;
|
||||||
|
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
|
||||||
|
final class EndPlatformMembershipCommandTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
use ContainerTrait;
|
||||||
|
use ContainerRepositoryTrait;
|
||||||
|
use RefreshDatabaseTrait;
|
||||||
|
|
||||||
|
public function testExecute(): void
|
||||||
|
{
|
||||||
|
$kernel = self::bootKernel();
|
||||||
|
$this->fixDoctrineBug($kernel->getContainer());
|
||||||
|
|
||||||
|
// temporarily set global configuration as globalPaidMembership = true
|
||||||
|
$configuration = $this->getConfigurationRepository()->getInstanceConfigurationOrCreate();
|
||||||
|
$newConfig = $configuration->getConfiguration();
|
||||||
|
$newConfig['global']['globalPaidMembership'] = true;
|
||||||
|
$configuration->setConfiguration($newConfig);
|
||||||
|
$this->getConfigurationRepository()->save($configuration, true);
|
||||||
|
|
||||||
|
$application = new Application($kernel);
|
||||||
|
$command = $application->find(EndPlatformMembershipCommand::CMD);
|
||||||
|
$commandTester = new CommandTester($command);
|
||||||
|
$commandTester->execute([]);
|
||||||
|
$commandTester->assertCommandIsSuccessful();
|
||||||
|
self::assertEmailCount(1);
|
||||||
|
self::assertNotificationCount(1);
|
||||||
|
$output = $commandTester->getDisplay();
|
||||||
|
self::assertStringContainsString(\sprintf('%d update', 1), $output);
|
||||||
|
|
||||||
|
// already deleted
|
||||||
|
$commandTester->execute([]);
|
||||||
|
$commandTester->assertCommandIsSuccessful();
|
||||||
|
self::assertEmailCount(1); // not +1
|
||||||
|
self::assertNotificationCount(1);
|
||||||
|
$output = $commandTester->getDisplay();
|
||||||
|
self::assertStringContainsString(\sprintf('%d update', 0), $output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Integration\Command;
|
||||||
|
|
||||||
|
use App\Command\NotifyPlatformMembershipExpirationCommand;
|
||||||
|
use App\Test\ContainerRepositoryTrait;
|
||||||
|
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
|
||||||
|
final class NotifyPlatformMembershipExpirationCommandTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
use ContainerRepositoryTrait;
|
||||||
|
use RefreshDatabaseTrait;
|
||||||
|
|
||||||
|
public function testExecute(): void
|
||||||
|
{
|
||||||
|
$kernel = self::bootKernel();
|
||||||
|
// temporarily set global configuration as globalPaidMembership = true
|
||||||
|
$configuration = $this->getConfigurationRepository()->getInstanceConfigurationOrCreate();
|
||||||
|
$newConfig = $configuration->getConfiguration();
|
||||||
|
$newConfig['global']['globalPaidMembership'] = true;
|
||||||
|
$configuration->setConfiguration($newConfig);
|
||||||
|
$this->getConfigurationRepository()->save($configuration, true);
|
||||||
|
|
||||||
|
$application = new Application($kernel);
|
||||||
|
$command = $application->find(NotifyPlatformMembershipExpirationCommand::CMD);
|
||||||
|
$commandTester = new CommandTester($command);
|
||||||
|
|
||||||
|
// in one week
|
||||||
|
$commandTester->execute([
|
||||||
|
'days' => 7,
|
||||||
|
]);
|
||||||
|
$commandTester->assertCommandIsSuccessful();
|
||||||
|
$output = $commandTester->getDisplay();
|
||||||
|
self::assertStringContainsString(\sprintf('%d notification', 1), $output);
|
||||||
|
self::assertStringContainsString(\sprintf('notifying platform membership expiration for user %s', 'Kevin'), $output);
|
||||||
|
self::assertEmailCount(1);
|
||||||
|
self::assertNotificationCount(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Integration\MessageHandler\Payment;
|
||||||
|
|
||||||
|
use App\Entity\Payment;
|
||||||
|
use App\Entity\PaymentToken;
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Message\Command\Payment\PlatformMembershipPaidCommand;
|
||||||
|
use App\MessageHandler\Command\Payment\PlatformMembershipPaidCommandHandler;
|
||||||
|
use App\Test\ContainerRepositoryTrait;
|
||||||
|
use App\Tests\TestReference;
|
||||||
|
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
|
||||||
|
final class PlatformMembershipPaidCommandHandlerTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabaseTrait;
|
||||||
|
use ContainerRepositoryTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just to test when the status is not "captured".
|
||||||
|
*/
|
||||||
|
public function testDoneStatusFailed(): void
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$handler = self::getContainer()->get(PlatformMembershipPaidCommandHandler::class);
|
||||||
|
self::assertInstanceOf(PlatformMembershipPaidCommandHandler::class, $handler);
|
||||||
|
|
||||||
|
$platformOffer = $this->getPlatformOfferRepository()->get(TestReference::PLATFORM_OFFER_1);
|
||||||
|
$user = $this->getUserRepository()->get(TestReference::ADMIN_LOIC);
|
||||||
|
|
||||||
|
$message = new PlatformMembershipPaidCommand($platformOffer->getId(), $user->getId(), $this->getToken($user));
|
||||||
|
$status = $handler($message);
|
||||||
|
self::assertTrue($status->isNew());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getToken(User $user): PaymentToken
|
||||||
|
{
|
||||||
|
$token = new PaymentToken();
|
||||||
|
$token->setGatewayName('offline');
|
||||||
|
$payment = new Payment();
|
||||||
|
$payment->setUser($user);
|
||||||
|
$token->setDetails($payment);
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No error 500 if the user is already a member.
|
||||||
|
*/
|
||||||
|
public function testDoneAlreadyMember(): void
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$handler = self::getContainer()->get(PlatformMembershipPaidCommandHandler::class);
|
||||||
|
self::assertInstanceOf(PlatformMembershipPaidCommandHandler::class, $handler);
|
||||||
|
|
||||||
|
$platformOffer = $this->getPlatformOfferRepository()->get(TestReference::PLATFORM_OFFER_1);
|
||||||
|
$user = $this->getUserRepository()->get(TestReference::ADMIN_LOIC);
|
||||||
|
$user->setMembershipPaid(false); // juste for the test
|
||||||
|
$this->getUserManager()->save($user, true);
|
||||||
|
$payment = $this->getPaymentRepository()->get(TestReference::PAYMENT_USER_16_1);
|
||||||
|
$token = new PaymentToken();
|
||||||
|
$token->setGatewayName('offline');
|
||||||
|
$payment->setUser($user);
|
||||||
|
$token->setDetails($payment);
|
||||||
|
|
||||||
|
$message = new PlatformMembershipPaidCommand($platformOffer->getId(), $user->getId(), $token);
|
||||||
|
$status = $handler($message);
|
||||||
|
self::assertTrue($status->isCaptured());
|
||||||
|
self::assertEmailCount(1);
|
||||||
|
self::assertTrue($user->isMembershipPaid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,6 @@ final class MeilisearchTest extends KernelTestCase
|
||||||
$meilisearch->indexProducts([$object, $service]);
|
$meilisearch->indexProducts([$object, $service]);
|
||||||
$searchDto = new Search('vélo');
|
$searchDto = new Search('vélo');
|
||||||
$results = $meilisearch->search($searchDto);
|
$results = $meilisearch->search($searchDto);
|
||||||
self::assertNotEmpty($results->getHitsCount());
|
self::assertNotEmpty($results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Tests\Unit\Controller\Payment;
|
namespace App\Tests\Unit\Controller\Payment\Group;
|
||||||
|
|
||||||
use App\Controller\Payment\Group\DoneAction;
|
use App\Controller\Payment\Group\DoneAction;
|
||||||
use App\Entity\Group;
|
use App\Entity\Group;
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Unit\Controller\Payment\PlatformMembership;
|
||||||
|
|
||||||
|
use App\Controller\Payment\PlatformMembership\DoneAction;
|
||||||
|
use App\Entity\PaymentToken;
|
||||||
|
use App\Entity\PlatformOffer;
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\MessageBus\CommandBusInterface;
|
||||||
|
use Payum\Core\Payum;
|
||||||
|
use Payum\Core\Request\GetHumanStatus;
|
||||||
|
use Payum\Core\Security\HttpRequestVerifierInterface;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||||
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
class DoneActionTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Too complicated, the controller should be refactored.
|
||||||
|
*/
|
||||||
|
public function testUnprocessableEntityHttpException(): void
|
||||||
|
{
|
||||||
|
$httpRequestVerifierInterface = $this->getMockBuilder(HttpRequestVerifierInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$httpRequestVerifierInterface->method('verify')
|
||||||
|
->willThrowException(new UnprocessableEntityHttpException());
|
||||||
|
|
||||||
|
$payum = $this->getMockBuilder(Payum::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$payum->method('getHttpRequestVerifier')
|
||||||
|
->willReturn($httpRequestVerifierInterface);
|
||||||
|
|
||||||
|
$translator = $this->getMockBuilder(TranslatorInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$doneAction = new DoneAction(
|
||||||
|
$this->getCommandBus(),
|
||||||
|
$payum,
|
||||||
|
$translator,
|
||||||
|
$this->getLogger(),
|
||||||
|
);
|
||||||
|
$this->expectException(\RuntimeException::class);
|
||||||
|
$this->expectExceptionMessage('Cannot verify Payum token');
|
||||||
|
|
||||||
|
$doneAction->__invoke(new Request(), $this->getPlatformOffer(), $this->getUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All this to test a line :/.
|
||||||
|
*/
|
||||||
|
public function testFlashWarning(): void
|
||||||
|
{
|
||||||
|
$httpRequestVerifierInterface = $this->getMockBuilder(HttpRequestVerifierInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$httpRequestVerifierInterface->method('verify')
|
||||||
|
->willReturn(new PaymentToken());
|
||||||
|
|
||||||
|
$payum = $this->getMockBuilder(Payum::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$payum->method('getHttpRequestVerifier')
|
||||||
|
->willReturn($httpRequestVerifierInterface);
|
||||||
|
|
||||||
|
$translator = $this->getMockBuilder(TranslatorInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$comandBus = $this->getCommandBus();
|
||||||
|
$comandBus->method('dispatch')->willReturn(new GetHumanStatus(new PaymentToken()));
|
||||||
|
|
||||||
|
$doneAction = new DoneAction(
|
||||||
|
$this->getCommandBus(),
|
||||||
|
$payum,
|
||||||
|
$translator,
|
||||||
|
$this->getLogger(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// set session!
|
||||||
|
$session = $this->getMockBuilder(FlashBagAwareSessionInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$session->method('getFlashBag')->willReturn(new FlashBag());
|
||||||
|
|
||||||
|
$requesStack = $this->getMockBuilder(RequestStack::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$requesStack->method('getSession')->willReturn($session);
|
||||||
|
$container = $this->getMockBuilder(ContainerInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$container->method('get')->willReturn($requesStack);
|
||||||
|
$doneAction->setContainer($container);
|
||||||
|
|
||||||
|
$this->expectException(\Error::class); // or more mock are needed. To clean up later
|
||||||
|
|
||||||
|
$doneAction->__invoke(new Request(), $this->getPlatformOffer(), $this->getUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CommandBusInterface&MockObject
|
||||||
|
*/
|
||||||
|
private function getCommandBus(): MockObject
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder(CommandBusInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLogger(): MockObject&LoggerInterface
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder(LoggerInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUser(): User
|
||||||
|
{
|
||||||
|
return (new User())
|
||||||
|
->setId($this->getUuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUuid(): Uuid
|
||||||
|
{
|
||||||
|
return Uuid::v6();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPlatformOffer(): PlatformOffer
|
||||||
|
{
|
||||||
|
$platformOffer = new PlatformOffer();
|
||||||
|
$platformOffer->setId($this->getUuid());
|
||||||
|
|
||||||
|
return $platformOffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -373,6 +373,11 @@
|
||||||
<target>Nombre de groupes</target>
|
<target>Nombre de groupes</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="mFV6gsn" resname="Membership Paid">
|
||||||
|
<source>Membership Paid</source>
|
||||||
|
<target>Abonnement à la plateforme payé</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="Zs247Lc" resname="app.controller.admin.user_crud_controller.expires_in.formatted_value">
|
||||||
|
<source>app.controller.admin.user_crud_controller.expires_in.formatted_value</source>
|
||||||
|
<target>%days% jour(s).</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<body>
|
<body>
|
||||||
<trans-unit id="HkHjuo7" resname="app.controller.payment.platform_membership.done_action.flash.success">
|
<trans-unit id="HkHjuo7" resname="app.controller.payment.platform_membership.done_action.flash.success">
|
||||||
<source>app.controller.payment.platform_membership.done_action.flash.success</source>
|
<source>app.controller.payment.platform_membership.done_action.flash.success</source>
|
||||||
<target>Paiement réussi. Vous êtes désormais membre de la plateforme %platform%.</target>
|
<target>Paiement réussi. Vous êtes désormais membre de la plateforme %platform%. Veuillez renseigner votre adresse afin de pouvoir utiliser les différents services.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
<trans-unit id="iikpmn8" resname="app.controller.payment.platform_membership.done_action.status.new">
|
<trans-unit id="iikpmn8" resname="app.controller.payment.platform_membership.done_action.status.new">
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,21 @@
|
||||||
<target>Votre compte a bien été créé. Veuillez renseigner votre adresse afin de pouvoir utiliser les différents services.</target>
|
<target>Votre compte a bien été créé. Veuillez renseigner votre adresse afin de pouvoir utiliser les différents services.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
<trans-unit id="" resname="app.controller.security.account_create_controller.step2.with_invitation.flash.success">
|
<trans-unit id="jaHXivi" resname="app.controller.security.account_create_controller.step2.global_paid_membership.flash.success">
|
||||||
|
<source>app.controller.security.account_create_controller.step2.global_paid_membership.flash.success</source>
|
||||||
|
<target>Votre compte a bien été créé. Pour accéder à la plateforme, veuillez payer l'adhésion.</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="ueGTY73" resname="app.controller.security.account_create_controller.step2.with_invitation.flash.success">
|
||||||
<source>app.controller.security.account_create_controller.step2.with_invitation.flash.success</source>
|
<source>app.controller.security.account_create_controller.step2.with_invitation.flash.success</source>
|
||||||
<target>Votre compte a bien été créé. Vous pouvez accepter l'invitation sur la page du groupe.</target>
|
<target>Votre compte a bien été créé. Vous pouvez accepter l'invitation sur la page du groupe.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="MWzA9dr" resname="app.controller.security.account_create_controller.step2.with_invitation.global_paid_membership.flash.success">
|
||||||
|
<source>app.controller.security.account_create_controller.step2.with_invitation.global_paid_membership.flash.success</source>
|
||||||
|
<target>Votre compte a bien été créé. Pour accéder à la plateforme, veuillez payer l'adhésion. Vous pourrez alors accepter l'invitation sur la page du groupe.</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
<trans-unit id="jDAjgu1" resname="app.controller.security.account_create_controller.step2.user_not_found.warning">
|
<trans-unit id="jDAjgu1" resname="app.controller.security.account_create_controller.step2.user_not_found.warning">
|
||||||
<source>app.controller.security.account_create_controller.step2.user_not_found.warning</source>
|
<source>app.controller.security.account_create_controller.step2.user_not_found.warning</source>
|
||||||
<target>Aucun·e utilisateur·rice correspondant à ce code n'a été trouvé·e. Si votre compte est déjà confirmé veuillez vous connecter.</target>
|
<target>Aucun·e utilisateur·rice correspondant à ce code n'a été trouvé·e. Si votre compte est déjà confirmé veuillez vous connecter.</target>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="DdQRDUh" resname="app.mailer.email.command.end_platform_membership_mail.subject">
|
||||||
|
<source>app.mailer.email.command.end_platform_membership_mail.subject</source>
|
||||||
|
<target>%brand% : Expiration de votre adhésion à la plateforme %platform%.</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="6AMBY16" resname="app.mailer.email.command.notify_platform_membership_expiration_mail.subject">
|
||||||
|
<source>app.mailer.email.command.notify_platform_membership_expiration_mail.subject</source>
|
||||||
|
<target>%brand% : expiration de l'adhésion à la plateforme %platform% dans %days% jour(s).</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="P5fekcX" resname="app.mailer.email.payment.platform_membership_paid_mail.subject">
|
||||||
|
<source>app.mailer.email.command.platform_membership_paid_mail.subject</source>
|
||||||
|
<target>%brand% : Confirmation de votre adhésion à la plateforme %platform%.</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="dMFTkCX" resname="templates.email.command.end_platform_membership.h1">
|
||||||
|
<source>emplates.email.command.end_platform_membership.h1</source>
|
||||||
|
<target>Bonjour !</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="nAjYzR4" resname="templates.email.command.end_platform_membership.p1">
|
||||||
|
<source>templates.email.command.end_platform_membership.p1</source>
|
||||||
|
<target>Votre adhésion à la plateforme %platform% a expiré le %endAt%.
|
||||||
|
Connectez-vous à votre compte pour renouveler votre adhésion. </target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="kcvM4iP" resname="templates.email.command.end_platform_membership.loginLink">
|
||||||
|
<source>templates.email.command.end_platform_membership.loginLink</source>
|
||||||
|
<target>Me connecter</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="cmeQr4r" resname="templates.email.command.notify_membership_expiration.h1">
|
||||||
|
<source>templates.email.command.notify_membership_expiration.h1</source>
|
||||||
|
<target>Bonjour !</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="YUhVmRj" resname="templates.email.command.notify_membership_expiration.p1">
|
||||||
|
<source>templates.email.command.notify_membership_expiration.p1</source>
|
||||||
|
<target>Votre adhésion à la plateform %platform% expire dans %days% jour(s).</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="n6g8FMV" resname="templates.email.payment.platform_membership_paid.h1">
|
||||||
|
<source>emplates.email.payment.platform_membership_paid.h1</source>
|
||||||
|
<target>Bonjour !</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="8yoMsLT" resname="templates.email.payment.platform_membership_paid.p1">
|
||||||
|
<source>templates.email.payment.platform_membership_paid.p1</source>
|
||||||
|
<target>Votre adhésion à la plateforme %platform% a bien été pris en compte le %startAt%.
|
||||||
|
Il expirera le %endAt%</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
16
translations/user/validators.fr.xlf
Normal file
16
translations/user/validators.fr.xlf
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
|
<file source-language="en" target-language="fr" datatype="plaintext" original="file.ext">
|
||||||
|
<header>
|
||||||
|
<tool tool-id="symfony" tool-name="Symfony" />
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<trans-unit id="qTjiw69" resname="validator.user.membership_paid">
|
||||||
|
<source>validator.user.membership_paid</source>
|
||||||
|
<target>Veuillez remplir ce champ</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
Loading…
Reference in a new issue