Compare commits
483 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a6628ec70 | ||
|
|
fcb9a15bd5 | ||
|
|
653bdead7d | ||
|
|
600efe894c | ||
|
|
14b2c8c2c7 | ||
|
|
dff97f2501 | ||
|
|
027edccd7a | ||
|
|
ca78be22fd | ||
|
|
7cf5db11a6 | ||
|
|
a0f8a47683 | ||
|
|
e98ad69729 | ||
|
|
707da5e9e9 | ||
|
|
bc2302ef7a | ||
|
|
9f8196a175 | ||
|
|
0ad6161276 | ||
|
|
63d153b3d3 | ||
|
|
74a51852c8 | ||
|
|
bf2b05dca4 | ||
|
|
92b9929849 | ||
|
|
ffe65f6ec6 | ||
|
|
ee4a4aa729 | ||
|
|
3d79f8bde3 | ||
|
|
fd10784602 | ||
|
|
5fa3a40871 | ||
|
|
dafb2fe840 | ||
|
|
eed05cb64a | ||
|
|
2f27550ef4 | ||
|
|
81d82640f1 | ||
|
|
9ebd895b6f | ||
|
|
bcd4341539 | ||
|
|
515a265ea0 | ||
|
|
90caf6e30d | ||
|
|
05da2e261f | ||
|
|
ca5d343138 | ||
|
|
d3cb440627 | ||
|
|
d52bc07c71 | ||
|
|
916620bdb6 | ||
|
|
4c66ce1903 | ||
|
|
2edd1bc5b4 | ||
|
|
a0ed503b79 | ||
|
|
6e7205ffac | ||
|
|
6c6e273b7a | ||
|
|
73087d35d5 | ||
|
|
60c5a5c568 | ||
|
|
42a394df31 | ||
|
|
5da192d452 | ||
|
|
5b6f4b1a40 | ||
|
|
9cb936965c | ||
|
|
23ed442eb7 | ||
|
|
a54f2656e0 | ||
|
|
6cfc3e381e | ||
|
|
0055add48f | ||
|
|
f13f4c55af | ||
|
|
512274a11f | ||
|
|
69c09b8e25 | ||
|
|
16d01d96b9 | ||
|
|
e42fdc4c15 | ||
|
|
c1ac3d3a20 | ||
|
|
2bc6d64904 | ||
|
|
bea7e22cbb | ||
|
|
99a8a0da47 | ||
|
|
5af3ffa261 | ||
|
|
622f75c298 | ||
|
|
68c8705dd3 | ||
|
|
9a0f882025 | ||
|
|
770bf8e825 | ||
|
|
94fdd964cb | ||
|
|
b2ab49ca58 | ||
|
|
f17f697de1 | ||
|
|
038d9911c0 | ||
|
|
8e39d417e2 | ||
|
|
5e4af3e91e | ||
|
|
fa18aef1a4 | ||
|
|
105907413c | ||
|
|
776f3344c6 | ||
|
|
aec728ff19 | ||
|
|
397738ef90 | ||
|
|
0d31003dd3 | ||
|
|
a4c937aac6 | ||
|
|
75c9eefa39 | ||
|
|
52b38fdc53 | ||
|
|
ff0f58afe2 | ||
|
|
f7639af7d8 | ||
|
|
00d9a61806 | ||
|
|
ad6df7a926 | ||
|
|
d1095dd4d2 | ||
|
|
f318750b1d | ||
|
|
41d379fb13 | ||
|
|
1f38e2380c | ||
|
|
4fc504bf9a | ||
|
|
5e5493ff82 | ||
|
|
cbc8f85cc0 | ||
|
|
6472f29fdf | ||
|
|
ae047d5b21 | ||
|
|
c0316d2f09 | ||
|
|
33d530093e | ||
|
|
51163f325a | ||
|
|
d771f14cce | ||
|
|
9f58c867e1 | ||
|
|
d07f72513b | ||
|
|
ac20e3d0b8 | ||
|
|
c3f227fbf3 | ||
|
|
09dd7836e1 | ||
|
|
402bb46b9b | ||
|
|
7033f76d44 | ||
|
|
2e1b82e6f2 | ||
|
|
def7703d7f | ||
|
|
22aaa35daa | ||
|
|
5a99e26334 | ||
|
|
e4cf01c298 | ||
|
|
d7510f0c8d | ||
|
|
fc0fb741f2 | ||
|
|
dade724563 | ||
|
|
5d10af5057 | ||
|
|
fa51a98d04 | ||
|
|
0f556f5458 | ||
|
|
ef1c2896fc | ||
|
|
95f8e54167 | ||
|
|
30108412a6 | ||
|
|
9ef16ef775 | ||
|
|
e81cb02ce2 | ||
|
|
5746177b73 | ||
|
|
99548a0c84 | ||
|
|
403b59696c | ||
|
|
33e7c76830 | ||
|
|
31bf60efd2 | ||
|
|
ca2147bf5a | ||
|
|
a312865bdf | ||
|
|
9950bb3d61 | ||
|
|
53d8316131 | ||
|
|
fb5563eb51 | ||
|
|
0d68d4dc6a | ||
|
|
808e71143e | ||
|
|
86adb38433 | ||
|
|
f238859798 | ||
|
|
58bc2b9a31 | ||
|
|
a275b8574c | ||
|
|
0766296a38 | ||
|
|
439ef4c7f2 | ||
|
|
6ba2d50633 | ||
|
|
2c2f73672f | ||
|
|
9780729fde | ||
|
|
6f4be83970 | ||
|
|
3dcda6191c | ||
|
|
99559db6b1 | ||
|
|
820a39e39f | ||
|
|
1dee3593e2 | ||
|
|
49f13d5dc7 | ||
|
|
ec13c57179 | ||
|
|
443f3a3c21 | ||
|
|
0303ffb348 | ||
|
|
5f6d9fa0db | ||
|
|
cab5e65258 | ||
|
|
b028acd55d | ||
|
|
1d9a7f6659 | ||
|
|
1fbe1f987d | ||
|
|
b603320aee | ||
|
|
e0d03de207 | ||
|
|
e49588ab14 | ||
|
|
c40646c1b7 | ||
|
|
2e41ac9267 | ||
|
|
f0cb5cdd61 | ||
|
|
de9b0a842d | ||
|
|
0e8ba02cf4 | ||
|
|
71794701b5 | ||
|
|
be58a967f4 | ||
|
|
fb105d31dd | ||
|
|
d8b8cbc584 | ||
|
|
db3a8763cf | ||
|
|
f5f00e685a | ||
|
|
9bc60dbaa0 | ||
|
|
6838280386 | ||
|
|
338c7899cd | ||
|
|
0787855b98 | ||
|
|
0863a06362 | ||
|
|
9f476854c0 | ||
|
|
e7e3ad721e | ||
|
|
49d0e7de50 | ||
|
|
13f1868342 | ||
|
|
ae218ff416 | ||
|
|
536bcde8da | ||
|
|
5a08860dd6 | ||
|
|
d20e9b08da | ||
|
|
1620123d3f | ||
|
|
68217f25cb | ||
|
|
79c70ea485 | ||
|
|
4f151512d2 | ||
|
|
c48ffdb30b | ||
|
|
f90e808cd0 | ||
|
|
2b1a47f48c | ||
|
|
2256ebe3b0 | ||
|
|
fe92159bec | ||
|
|
fba6061c1f | ||
|
|
78da14d357 | ||
|
|
1f85380a2c | ||
|
|
b1269cfa8c | ||
|
|
d4a98afc45 | ||
|
|
d90697de7c | ||
|
|
373ad67b8a | ||
|
|
5203f8e5b3 | ||
|
|
a731e2a5ee | ||
|
|
e612b9490f | ||
|
|
2bdae2ec6b | ||
|
|
64b00ed102 | ||
|
|
d52c2f8734 | ||
|
|
8bab835d61 | ||
|
|
180a5d9f55 | ||
|
|
28213946df | ||
|
|
4194cd559a | ||
|
|
e7e5ce5cfe | ||
|
|
59ce99524a | ||
|
|
499a8ff66e | ||
|
|
7c4fffd25e | ||
|
|
279f0f40f9 | ||
|
|
913836d7b4 | ||
|
|
cd22eb5767 | ||
|
|
b08c4ba454 | ||
|
|
4eca6543c8 | ||
|
|
e60d8c293d | ||
|
|
30fbe680db | ||
|
|
a1d776cefa | ||
|
|
7cf6546f81 | ||
|
|
bc932ff48f | ||
|
|
b772790b76 | ||
|
|
c22859d810 | ||
|
|
ac64ea1d7e | ||
|
|
276003152a | ||
|
|
b8a20d6a18 | ||
|
|
78fc610454 | ||
|
|
7e21eff64c | ||
|
|
0b615de4c3 | ||
|
|
f371cd118d | ||
|
|
47ca160dd8 | ||
|
|
399a0cd377 | ||
|
|
1815df9201 | ||
|
|
eea7479319 | ||
|
|
f36c617f4f | ||
|
|
6bbe6d70e5 | ||
|
|
24f5fc235b | ||
|
|
e201833635 | ||
|
|
4c4aa6143d | ||
|
|
0b21b8f133 | ||
|
|
eaacb4d5af | ||
|
|
bfe4bd609f | ||
|
|
8473683d10 | ||
|
|
0ac449d097 | ||
|
|
d7edd72ec5 | ||
|
|
4c4f97387c | ||
|
|
a312b862b2 | ||
|
|
7a9f52041f | ||
|
|
f2bf1513aa | ||
|
|
b757d7df9d | ||
|
|
3906c96a6e | ||
|
|
d3253333ba | ||
|
|
b910075b7f | ||
|
|
becd807175 | ||
|
|
853d813282 | ||
|
|
68ec206f02 | ||
|
|
80631d4118 | ||
|
|
4a3ebac562 | ||
|
|
dab6f5aa0e | ||
|
|
71c30290ed | ||
|
|
687ac68e09 | ||
|
|
6e6c140eaf | ||
|
|
f66d470b3d | ||
|
|
1c9bbf5f41 | ||
|
|
500e0c18af | ||
|
|
b9262fc0c0 | ||
|
|
a1f94db388 | ||
|
|
34ca7c8238 | ||
|
|
bc9975b76e | ||
|
|
7a9c71da37 | ||
|
|
fb98660ed6 | ||
|
|
9022c7bedd | ||
|
|
d42aa9cb23 | ||
|
|
f07a8f62d5 | ||
|
|
d227ca624b | ||
|
|
38a5e9adea | ||
|
|
96d11aca11 | ||
|
|
6ede878a48 | ||
|
|
a3732674b1 | ||
|
|
3c7c1f52f0 | ||
|
|
abe383d79b | ||
|
|
03c8b4b57c | ||
|
|
4a1ab3e536 | ||
|
|
a1b5cf3e11 | ||
|
|
84aa9df1dc | ||
|
|
8c0760ef9b | ||
|
|
23c8826d4e | ||
|
|
33d2f4e573 | ||
|
|
97361f7a56 | ||
|
|
f6e8726096 | ||
|
|
c8c3393630 | ||
|
|
515d5400ab | ||
|
|
95a060dba3 | ||
|
|
4b67509c64 | ||
|
|
fb43e76037 | ||
|
|
ba6c249ec5 | ||
|
|
2981f3a540 | ||
|
|
3ffffc51be | ||
|
|
e35c13a3db | ||
|
|
84bbbbf025 | ||
|
|
fabf86778b | ||
|
|
fd8db72774 | ||
|
|
6c39b88daf | ||
|
|
6e3c8ec8a5 | ||
|
|
7a4ecef362 | ||
|
|
8dec9842df | ||
|
|
dab427f1d3 | ||
|
|
0a6eb9b890 | ||
|
|
34af665395 | ||
|
|
bcb8a28137 | ||
|
|
a77c6f3efa | ||
|
|
2c374fb502 | ||
|
|
af0b9c5838 | ||
|
|
8c4ca3d2aa | ||
|
|
c9c52d49ed | ||
|
|
5f24fdb4b4 | ||
|
|
1455242f5e | ||
|
|
b221b35391 | ||
|
|
e3e801d6d5 | ||
|
|
81b226d25b | ||
|
|
7564c25e9d | ||
|
|
0f4c859554 | ||
|
|
59d56abc87 | ||
|
|
c95d100611 | ||
|
|
a9a8bb9c79 | ||
|
|
5414ef54db | ||
|
|
cdd69b66d0 | ||
|
|
74dc29781b | ||
|
|
4168551267 | ||
|
|
ba52c85e42 | ||
|
|
2b09eae3e1 | ||
|
|
7ad3ee9f2e | ||
|
|
c1d542cd38 | ||
|
|
c8bd8e2dd6 | ||
|
|
5ec189b645 | ||
|
|
a8955ea980 | ||
|
|
ec00bfc061 | ||
|
|
6ffe20651a | ||
|
|
5ab24d021c | ||
|
|
b00d7fc1d8 | ||
|
|
08c617a43e | ||
|
|
7447bfae49 | ||
|
|
a930a6edbf | ||
|
|
cef265728e | ||
|
|
be3cda8574 | ||
|
|
7aac8fcbca | ||
|
|
fd955c15fd | ||
|
|
620ce0ef3c | ||
|
|
95f4a3372f | ||
|
|
e21018d98d | ||
|
|
4bd8761682 | ||
|
|
2dc9244226 | ||
|
|
3aa8caf539 | ||
|
|
352b1fc5b8 | ||
|
|
871a40d0a3 | ||
|
|
d01ff65c6a | ||
|
|
9f1e79eae1 | ||
|
|
5898bdd087 | ||
|
|
a5fa7d51de | ||
|
|
891fea9d58 | ||
|
|
d29f664737 | ||
|
|
4aaf428202 | ||
|
|
1815f72648 | ||
|
|
35974c391b | ||
|
|
4d746a6c85 | ||
|
|
c29a727a24 | ||
|
|
a7defcfdb7 | ||
|
|
c19ae8f690 | ||
|
|
676b2d0797 | ||
|
|
1c96b2253d | ||
|
|
3c23b8aee2 | ||
|
|
b594590b88 | ||
|
|
5aac86e2b1 | ||
|
|
50466a79b3 | ||
|
|
82199d2369 | ||
|
|
00ef145a1e | ||
|
|
03c9cd528d | ||
|
|
f0b839e9e9 | ||
|
|
225376b3d1 | ||
|
|
704e8b040b | ||
|
|
255bbf59d7 | ||
|
|
81e0be876f | ||
|
|
d1d637bf03 | ||
|
|
c75492a969 | ||
|
|
93c94dca8b | ||
|
|
67185c5cc3 | ||
|
|
9b69c8b012 | ||
|
|
058ab2ebf1 | ||
|
|
fe80aad838 | ||
|
|
eb0a772659 | ||
|
|
745c9501fe | ||
|
|
91f7812f84 | ||
|
|
5ef07d400e | ||
|
|
818c5df641 | ||
|
|
70609378bd | ||
|
|
9867755696 | ||
|
|
066f8109ad | ||
|
|
02d6f0ae30 | ||
|
|
32c502818d | ||
|
|
47e0524140 | ||
|
|
c42194356f | ||
|
|
3149fa557b | ||
|
|
6f2d02e4f1 | ||
|
|
5cf13785bd | ||
|
|
9b9fd88e6b | ||
|
|
f78c14d9f7 | ||
|
|
b7a6fecc26 | ||
|
|
dceba75e3b | ||
|
|
6ed0a4fdf5 | ||
|
|
4ef00d6fea | ||
|
|
1bd4983cde | ||
|
|
3b905203a7 | ||
|
|
3c80fe8c4c | ||
|
|
c2aa74e1ce | ||
|
|
1f9bc0f04c | ||
|
|
7b54a77d7d | ||
|
|
ff5bf2418e | ||
|
|
9816bb93d5 | ||
|
|
237a17d815 | ||
|
|
2ebcf417c0 | ||
|
|
74f88ffc0e | ||
|
|
3d3f79cbdd | ||
|
|
a1a93195ac | ||
|
|
8349bf5ae7 | ||
|
|
29f07ad69a | ||
|
|
c23659c600 | ||
|
|
c944141342 | ||
|
|
04178116c9 | ||
|
|
d2272a7a13 | ||
|
|
3b243d6cca | ||
|
|
75b33bc116 | ||
|
|
f7ea8d0004 | ||
|
|
b0a72941b5 | ||
|
|
d681d55d68 | ||
|
|
529651895f | ||
|
|
d18a589869 | ||
|
|
fb45dd4ace | ||
|
|
6869c289f5 | ||
|
|
37725e43fe | ||
|
|
51bb5be052 | ||
|
|
e7fbe920e1 | ||
|
|
5aa0a479fd | ||
|
|
7d31eb4c72 | ||
|
|
2d4f9111f4 | ||
|
|
1b0a9d2a18 | ||
|
|
b2221b4fe8 | ||
|
|
a3fa02cfd5 | ||
|
|
950ff85cbd | ||
|
|
539f02539d | ||
|
|
9fefc205fd | ||
|
|
94d84e4251 | ||
|
|
3edc643bb3 | ||
|
|
fdf548fd0f | ||
|
|
c8e21e7df8 | ||
|
|
e0718decca | ||
|
|
a243880c58 | ||
|
|
fc1f071262 | ||
|
|
4be962e01d | ||
|
|
b3f79cb114 | ||
|
|
33b523ff82 | ||
|
|
7f456569b2 | ||
|
|
efe25f958a | ||
|
|
d3a963343c | ||
|
|
ac032cd6e6 | ||
|
|
94ae431d55 | ||
|
|
f043eeaa8d | ||
|
|
001691e342 | ||
|
|
ee17d3c445 | ||
|
|
7564d9eba3 | ||
|
|
bde869120e | ||
|
|
e28970ba13 | ||
|
|
149b54f3ed | ||
|
|
f99e259bd5 | ||
|
|
ffe82091fb | ||
|
|
7b48bb605a | ||
|
|
527d0eb828 | ||
|
|
aa98594f20 | ||
|
|
e8773a9f38 | ||
|
|
899bc41db5 | ||
|
|
3659beb7b5 | ||
|
|
397434d8db |
786 changed files with 63954 additions and 59453 deletions
|
|
@ -11,5 +11,8 @@ trim_trailing_whitespace = true
|
|||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.vue]
|
||||
indent_size = 2
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
|
|
|||
22
.env.example
22
.env.example
|
|
@ -3,7 +3,6 @@ APP_ENV=local
|
|||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=
|
||||
APP_THEME=basic
|
||||
|
||||
LOG_CHANNEL=daily
|
||||
LOG_LEVEL=debug
|
||||
|
|
@ -34,10 +33,21 @@ MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr
|
|||
MAIL_LIST_INVALIDINCO=equipe.web@ldc.fr,vincent.pierre@ldc.fr,christelle.manceau@ldc.fr
|
||||
|
||||
# CRM
|
||||
CRM_ENDPOINT=https://ldcldccrm:K5cJmTsG@dev.ldc-crm.fr
|
||||
# Service boutique
|
||||
CRM_ENDPOINT=
|
||||
CRM_TOKEN=
|
||||
# LDC Web Status Checker
|
||||
PROJECT_UUID=
|
||||
# Google Analytics
|
||||
CRM_PASSWORD=
|
||||
|
||||
# SENTRY
|
||||
SENTRY_LARAVEL_DSN=
|
||||
|
||||
# LDC WEB STATUS CHECKER
|
||||
LDC_STATUS_CHECKER_API_KEY="MY_KEY"
|
||||
LDC_STATUS_CHECKER_UUID="UUID_PROJECT"
|
||||
|
||||
# GOOGLE
|
||||
# - ANALYTICS
|
||||
ANALYTICS_GOOGLE_ID=
|
||||
# - RECAPTCHA
|
||||
GOOGLE_RECAPTCHA_PUBLIC=
|
||||
GOOGLE_RECAPTCHA_PRIVATE=
|
||||
GOOGLE_RECAPTCHA_VERSION=
|
||||
|
|
|
|||
41
.eslintrc.json
Normal file
41
.eslintrc.json
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/vue3-strongly-recommended",
|
||||
"@vue/eslint-config-typescript"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.vue"],
|
||||
"rules": {
|
||||
"no-undef": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.vue"],
|
||||
"rules": {
|
||||
"indent": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"parser": "vue-eslint-parser",
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["vue", "@typescript-eslint"],
|
||||
"ignorePatterns": ["webpack.mix.js", "**/vendor/*.js", "**/vendor/**/*.js"],
|
||||
"rules": {
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": ["error", "double"],
|
||||
"semi": ["error", "always"],
|
||||
"vue/script-indent": ["error", 2, { "baseIndent": 0, "switchCase": 1 }],
|
||||
"vue/one-component-per-file": "off"
|
||||
}
|
||||
}
|
||||
24
.gitignore
vendored
24
.gitignore
vendored
|
|
@ -1,22 +1,32 @@
|
|||
/node_modules
|
||||
/public/hot
|
||||
/public/storage
|
||||
/public/images/content
|
||||
/public/images/gammes
|
||||
/public/images/produits
|
||||
/public/images/slides
|
||||
/public/b-o/
|
||||
/public/mix-manifest.json
|
||||
/public/assets/*
|
||||
/public/js/*
|
||||
/public/css/*
|
||||
/public/fonts/*
|
||||
/public/content/*
|
||||
/public/images/*
|
||||
/public/cache/*
|
||||
/public/uploads/*
|
||||
mix-manifest.json
|
||||
/storage/*.key
|
||||
/storage/framework/laravel-excel/*
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.env.dev
|
||||
.env.prod
|
||||
.phpunit.result.cache
|
||||
docker-compose.override.yml
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
auth.json
|
||||
workspace.code-workspace
|
||||
.vscode
|
||||
# IGNORE THEME SUBMODULES CHANGES
|
||||
resources/theme
|
||||
# Ignore compiled mail theme
|
||||
resource/vendor/mail/html/themes/default.css
|
||||
auth.json
|
||||
|
|
|
|||
|
|
@ -1,46 +1,24 @@
|
|||
image: $CI_REGISTRY/service-web-lab/ldc-web-images-docker/ldcweb-qa:php7.3-1.0
|
||||
include:
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'lint/lint7.3.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'security/security7.3.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'build/build7.3.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'test/test.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'deploy/deploy.yml'
|
||||
|
||||
|
||||
stages:
|
||||
- Security
|
||||
- CodingStandards
|
||||
|
||||
composer-security:
|
||||
stage: Security
|
||||
script:
|
||||
- local-php-security-checker --format=json --path=./composer.lock > composer-security-checker-report.json
|
||||
artifacts:
|
||||
when: on_failure
|
||||
expose_as: 'composer-security-checker'
|
||||
paths:
|
||||
- composer-security-checker-report.json
|
||||
allow_failure: true
|
||||
|
||||
npm-security:
|
||||
stage: Security
|
||||
script:
|
||||
- audit-ci -p npm -o json > npm-security-checker-report.json
|
||||
artifacts:
|
||||
when: on_failure
|
||||
expose_as: 'npm-security-checker'
|
||||
paths:
|
||||
- npm-security-checker-report.json
|
||||
allow_failure: true
|
||||
|
||||
phpcs:
|
||||
stage: CodingStandards
|
||||
before_script:
|
||||
- composer config gitlab-token.gitlab.com $CI_DEPLOY_USER $CI_DEPLOY_PASSWORD
|
||||
- composer install
|
||||
cache:
|
||||
paths:
|
||||
- vendor/
|
||||
script:
|
||||
- vendor/bin/phpcs --report=junit --report-file=phpcs-report.xml
|
||||
artifacts:
|
||||
when: on_failure
|
||||
expose_as: 'phpcs'
|
||||
paths:
|
||||
- phpcs-report.xml
|
||||
reports:
|
||||
junit: phpcs-report.xml
|
||||
allow_failure: false
|
||||
- lint
|
||||
- security
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
|
|
|||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "resources/theme"]
|
||||
path = resources/theme
|
||||
url = ../boutique-cnc-themes.git
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
php:
|
||||
preset: laravel
|
||||
version: 8
|
||||
disabled:
|
||||
- no_unused_imports
|
||||
finder:
|
||||
|
|
|
|||
43
.stylelintrc.json
Normal file
43
.stylelintrc.json
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"extends": [
|
||||
"stylelint-config-standard-scss",
|
||||
"stylelint-config-sass-guidelines",
|
||||
"stylelint-config-idiomatic-order"
|
||||
],
|
||||
"plugins": ["stylelint-scss"],
|
||||
"files": ["**/*.css", "**/*.scss"],
|
||||
"ignoreFiles": [
|
||||
"**/vendor/*.css",
|
||||
"**/vendor/**/*.css",
|
||||
"**/vendor/*.scss",
|
||||
"**/vendor/**/*.scss",
|
||||
"**/vendor/*.sass",
|
||||
"**/vendor/**/*.sass",
|
||||
"**/vendor/*.less",
|
||||
"**/vendor/**/*.less"
|
||||
],
|
||||
"customSyntax": "postcss-scss",
|
||||
"rules": {
|
||||
"indentation": 4,
|
||||
"string-quotes": "double",
|
||||
"selector-max-id": null,
|
||||
"color-no-invalid-hex": true,
|
||||
"order/properties-alphabetical-order": null,
|
||||
"max-nesting-depth": 5,
|
||||
"selector-max-compound-selectors": 5,
|
||||
"declaration-colon-space-after": "always-single-line",
|
||||
"function-parentheses-space-inside": "never-single-line",
|
||||
"declaration-colon-newline-after": null,
|
||||
"value-list-comma-newline-after": null,
|
||||
"scss/double-slash-comment-empty-line-before": [
|
||||
"always",
|
||||
{
|
||||
"ignore": [
|
||||
"between-comments",
|
||||
"stylelint-commands",
|
||||
"inside-block"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,8 @@
|
|||
## 2.0.0
|
||||
- Removed Regate stuff
|
||||
- Removed Salaries stuff
|
||||
|
||||
|
||||
## 1.0.1
|
||||
- Change LDC CRM Client repository
|
||||
- composer update
|
||||
|
|
|
|||
36
README.md
36
README.md
|
|
@ -33,6 +33,12 @@ Project root :
|
|||
```
|
||||
npm install && npm run prod
|
||||
```
|
||||
|
||||
## Theme config
|
||||
|
||||
- To reload theme config on engine `php artisan config:sync`
|
||||
- Theme config can be dynamic in `theme.config.php` inserting `MiniCrud`inputs inside, these muste be tested.
|
||||
|
||||
## Back-Office
|
||||
|
||||
Création de compte
|
||||
|
|
@ -45,3 +51,33 @@ URL : /bo
|
|||
## Required systems
|
||||
|
||||
* supervisor
|
||||
|
||||
|
||||
## Notes implémentation
|
||||
|
||||
Les pages statiques sont disponible a tout moment: `$StaticPageGlobal`
|
||||
|
||||
# Fonts
|
||||
- Robot fonts are used in PDF generation documents.
|
||||
|
||||
# STRIPE
|
||||
php artisan cashier:webhook
|
||||
- Il faut creer les webhooks dans le bo de Stripe.
|
||||
- Personaliser la page de paiement https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public
|
||||
- Il faut faire des payments avec plusieurs cartes pour valider l'intégration et avoir les clés de production
|
||||
https://dashboard.stripe.com/test/developers pour ensuite activer le compte https://dashboard.stripe.com/account/onboarding/
|
||||
|
||||
# System pay
|
||||
- Il faut autoriser 194.50.38.0/24 a se co au serveur en HTTP requetes POST.
|
||||
|
||||
# TODO
|
||||
- Allow changing e-mail quand ca sera supporté sur CRM (use soundsystem mechanism)
|
||||
|
||||
# FIXME
|
||||
- Fix tout le code lié a Stripe suite aux evolutions
|
||||
- Pour poursuivre le developpement il faut avoir acces a un compte system pay (pour vérifier suite a d'eventuelles evolutions)
|
||||
- Vérifier si la transaction system pay existe pour l'annuler le cas echéant dans le tunnel de commande
|
||||
(Pour éviter que le client commence une transaction dans system pay, revient en arriere, utiliser autre chose, cela fait des transactions system pay qui n'existe pas dans system pay mais que dans la boutique,
|
||||
il faut qppeler system pay pour voir si la transaction existe et nettoyer ces transaction fantomes dans le tunnel de commande)
|
||||
- Refactoriser du code au maximum puis tout retester
|
||||
- Implementer des test unitaires au moins pour toute les methodes liés au modeles au transactions, au commandes, au différentes class de LIB
|
||||
|
|
|
|||
177
app/Auth/CrmUserProvider.php
Normal file
177
app/Auth/CrmUserProvider.php
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
|
||||
namespace App\Auth;
|
||||
|
||||
use App\Models\Customer\Customer;
|
||||
use Illuminate\Auth\EloquentUserProvider;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\UserProvider as UserProviderContract;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use LDC\LDCCRM\Enums\ApiError;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\CrmException;
|
||||
use LDC\LDCCRM\Models\Customer as CrmCustomer;
|
||||
|
||||
/**
|
||||
* Crm user provider to integrate nicely with Laravel
|
||||
*/
|
||||
class CrmUserProvider extends EloquentUserProvider implements UserProviderContract
|
||||
{
|
||||
/**
|
||||
* The model to use, specified in auth config guard.
|
||||
* @var string
|
||||
*/
|
||||
private $usedModel = Customer::class;
|
||||
|
||||
/**
|
||||
* Retrieve a user by the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
// * Let laravel find a model
|
||||
$model = parent::retrieveByCredentials($credentials) ??
|
||||
static::retrieveTrashed($credentials);
|
||||
|
||||
try {
|
||||
/** @var \LDC\LDCCRM\CrmApiV2 */
|
||||
$crm = app('crmAPI');
|
||||
|
||||
// Si pas de compte local.
|
||||
if (!$model) {
|
||||
$crmCustomer = $crm->getCustomer($credentials['email']);
|
||||
|
||||
if (!$crmCustomer) {
|
||||
// * Customer is not found on CRM.
|
||||
return null;
|
||||
}
|
||||
$model = $this->createLocalCustomer($crmCustomer);
|
||||
}
|
||||
|
||||
return $model;
|
||||
} catch (ApiErrorException $e) {
|
||||
// * Customer is not found.
|
||||
if ($e->getApiError()->equals(ApiError::modelNotFound())) {
|
||||
return null;
|
||||
}
|
||||
report($e);
|
||||
Log::error('Unhandled response ', $e->getApiError()->label);
|
||||
} catch (CrmException | \Exception $e) {
|
||||
report($e);
|
||||
// Une erreur critique est survenue avec la CRM.
|
||||
return null;
|
||||
} //end try
|
||||
Log::error(__CLASS__ . '::retrieveByCredentials reached end of possibilities.');
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a user against the given credentials.
|
||||
*
|
||||
* @param UserContract $model
|
||||
* @param array $credentials
|
||||
* @return boolean
|
||||
* @throws \RuntimeException If model provided is not a Customer or connection to server fails.
|
||||
* @throws \LDC\LDCCRM\Exceptions\CrmException On CRM call error.
|
||||
* @throws \Exception On CRM call error.
|
||||
*/
|
||||
public function validateCredentials(UserContract $model, array $credentials)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Model $model */
|
||||
if (\get_class($model) !== $this->usedModel) {
|
||||
throw new \RuntimeException('Cannot authenticate any thing else than ' . $this->usedModel);
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var \LDC\LDCCRM\CrmApiV2 */
|
||||
$crm = app('crmAPI');
|
||||
|
||||
// * If has trait soft delete and customer trashed, then restore customer.
|
||||
if (
|
||||
\in_array(\Illuminate\Database\Eloquent\SoftDeletes::class, \class_uses_recursive($model)) and
|
||||
$model->trashed()
|
||||
) {
|
||||
$model->restore();
|
||||
}
|
||||
|
||||
// * Ne devrait pas survenir, $crm->login throws ApiError::authFailed()
|
||||
return $crm->login($credentials['email'], $credentials['password']);
|
||||
} catch (ApiErrorException $e) {
|
||||
if (!$model->hashcode or !CrmCustomer::find($model->hashcode)) {
|
||||
$model->forceDelete();
|
||||
return false;
|
||||
}
|
||||
if ($e->getApiError()->equals(ApiError::authFailed())) {
|
||||
return false;
|
||||
}
|
||||
// ! Assert Authenticable model must be valided (MustValidate trait).
|
||||
if ($e->getApiError()->equals(ApiError::customerNotActivated())) {
|
||||
Session::flash('warning', \trans('vous devez activer votre compte'));
|
||||
return true;
|
||||
}
|
||||
} catch (CrmException | \Exception $e) {
|
||||
report($e);
|
||||
if (config('app.debug')) {
|
||||
throw $e;
|
||||
}
|
||||
return false;
|
||||
} //end try
|
||||
|
||||
Log::error(__CLASS__ . '::validateCredentials reached end of possibilities.');
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a local customer
|
||||
*
|
||||
* @param \LDC\LDCCRM\Models\Customer $crmCustomer
|
||||
* @return \Illuminate\Database\Eloquent\Model
|
||||
* @throws \Throwable If saving to DB failed.
|
||||
*/
|
||||
private function createLocalCustomer(\LDC\LDCCRM\Models\Customer $crmCustomer): Model
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Model $model */
|
||||
$model = $this->usedModel::firstOrNew([
|
||||
'email' => $crmCustomer->email
|
||||
]);
|
||||
$model->hashcode = $crmCustomer->hashcode;
|
||||
$model->saveOrFail();
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a trashed customer by the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
* @throws \ErrorException If cannot connect to LDAP.
|
||||
*/
|
||||
private function retrieveTrashed(array $credentials): ?Authenticatable
|
||||
{
|
||||
// * Make changes
|
||||
if (empty($credentials)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// First we will add each credential element to the query as a where clause.
|
||||
// Then we can execute the query and, if we found a customer, return it in a
|
||||
// Eloquent User "model" that will be utilized by the Guard instances.
|
||||
$query = $this->createModel()->newQuery();
|
||||
|
||||
foreach ($credentials as $key => $value) {
|
||||
if (!Str::contains($key, 'password')) {
|
||||
$query->where($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var \App\Models\Customer|null $customer */
|
||||
return $query->withTrashed()->first();
|
||||
}
|
||||
}
|
||||
71
app/Auth/ReactivateCustomerProvider.php
Normal file
71
app/Auth/ReactivateCustomerProvider.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace App\Auth;
|
||||
|
||||
use App\Models\Customer\Customer;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Auth\EloquentUserProvider;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
|
||||
/**
|
||||
* Overload EloquentUserProvider to handle
|
||||
* Soft deleted Customers
|
||||
*/
|
||||
class ReactivateCustomerProvider extends EloquentUserProvider implements UserProvider
|
||||
{
|
||||
/**
|
||||
* Retrieve a customer by the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
* @throws \ErrorException If cannot connect to LDAP.
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
// * Make changes
|
||||
if (empty($credentials)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// First we will add each credential element to the query as a where clause.
|
||||
// Then we can execute the query and, if we found a customer, return it in a
|
||||
// Eloquent User "model" that will be utilized by the Guard instances.
|
||||
$query = $this->createModel()->newQuery();
|
||||
|
||||
foreach ($credentials as $key => $value) {
|
||||
if (!Str::contains($key, 'password')) {
|
||||
$query->where($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var \App\Models\Customer|null $customer */
|
||||
return $query->withTrashed()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a customer against the given credentials.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $customer
|
||||
* @param array $credentials
|
||||
* @return boolean
|
||||
* @throws \ErrorException If model provided is not a Customer or connection to server fails.
|
||||
*/
|
||||
public function validateCredentials(Authenticatable $customer, array $credentials)
|
||||
{
|
||||
/** @var \App\Models\Customer\Customer $customer */
|
||||
if ($customer instanceof Customer) {
|
||||
throw new \ErrorException('Cannot authenticate any thing else than ' . Customer::class);
|
||||
}
|
||||
|
||||
$plain = $credentials['password'];
|
||||
|
||||
/** @var \App\Models\Customer $customer */
|
||||
if ($this->hasher->check($plain, $customer->getAuthPassword())) {
|
||||
// * Restore customer
|
||||
return boolval($customer->restore());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
59
app/Casts/IntToEpochCast.php
Normal file
59
app/Casts/IntToEpochCast.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class IntToEpochCast implements CastsAttributes
|
||||
{
|
||||
/**
|
||||
* Cast the given value.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
|
||||
*/
|
||||
public function get($model, string $key, $value, array $attributes)
|
||||
{
|
||||
// phpcs:enable
|
||||
if (\is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
$epoch = Carbon::createFromTimestamp(0)->timezone('utc');
|
||||
$time = Carbon::now()->timezone('utc')->parse(\intval($value));
|
||||
$minutesDiff = $time->diffInMinutes($epoch);
|
||||
$hoursDiff = str_pad(floor($minutesDiff / 60), 2, '0', STR_PAD_LEFT);
|
||||
$minutesDiff = str_pad($minutesDiff % 60, 2, '0', STR_PAD_LEFT);
|
||||
return "{$hoursDiff}:{$minutesDiff}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given value for storage.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
|
||||
*/
|
||||
public function set($model, string $key, $value, array $attributes)
|
||||
{
|
||||
// phpcs:enable
|
||||
if (\is_null($value) or !\is_string($value)) {
|
||||
return null;
|
||||
}
|
||||
$time = explode(':', $value);
|
||||
$time = $time ? $time : [];
|
||||
return Carbon::createFromTimestamp(0)->timezone('utc')
|
||||
->setTime($time[0] ?? 0, $time[1] ?? 0)->timestamp;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class CreateAdmin extends Command
|
||||
{
|
||||
|
|
@ -13,14 +15,14 @@ class CreateAdmin extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'create:admin';
|
||||
protected $signature = 'user:create';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'creates an admin user upon password entry';
|
||||
protected $description = 'Create a backend admin user';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
|
|
@ -29,20 +31,78 @@ class CreateAdmin extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$firstname = $this->ask('What is the firstname?', 'Equipe');
|
||||
$lastname = $this->ask('What is the lastname?', 'Web');
|
||||
$email = $this->ask('What is the email?', 'equipe.web@ldc.fr');
|
||||
$pwd = $this->secret('What is the password?');
|
||||
$email = null;
|
||||
while (is_null($email)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user email', 'equipe.web@ldc.fr');
|
||||
$validator = Validator::make(['email' => $tmp], [
|
||||
'email' => 'required|unique:users,email|email:rfc,spoof'
|
||||
]);
|
||||
$validator->validate();
|
||||
$email = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid email %s',
|
||||
\implode(',', collect($e->errors())->flatten()->all())
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$firstname = null;
|
||||
while (is_null($firstname)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user firstname', 'Admin');
|
||||
$validator = Validator::make(['firstname' => $tmp], [
|
||||
'firstname' => 'required|min:5,max:255'
|
||||
]);
|
||||
$validator->validate();
|
||||
$firstname = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid firstname %s',
|
||||
\implode(',', collect($e->errors())->flatten()->all())
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$lastname = null;
|
||||
while (is_null($lastname)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user lastname', 'Saïtama');
|
||||
$validator = Validator::make(['lastname' => $tmp], [
|
||||
'lastname' => 'required|min:5,max:255'
|
||||
]);
|
||||
$validator->validate();
|
||||
$lastname = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid lastname %s',
|
||||
\implode(',', collect($e->errors())->flatten()->all())
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$password = null;
|
||||
while (
|
||||
($password = $this->secret(
|
||||
(!\is_null($password) ? 'Failed to confirm, ' : '') . 'Type the wanted user password'
|
||||
)) !== $this->secret('Confirm the password')
|
||||
) {
|
||||
continue;
|
||||
}; //end while
|
||||
|
||||
$user = new User();
|
||||
$user->firstname = $firstname;
|
||||
$user->lastname = $lastname;
|
||||
$user->date_of_birth = now();
|
||||
$user->email = $email;
|
||||
$user->password = Hash::make($pwd);
|
||||
$user->password = $password;
|
||||
$user->role = $this->confirm('Is the user an admin?') ?
|
||||
UserRole::admin() : UserRole::user();
|
||||
$user->email_verified_at = now();
|
||||
$user->role = 1;
|
||||
$user->save();
|
||||
$user->saveOrFail();
|
||||
|
||||
$this->info('User created.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Jobs\CsvSalariesReader as JobCsvSalarieReader;
|
||||
|
||||
class ImportSalaries extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'import:salaries';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Import Salaries, pour provision des clients';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Running the Job, this could take some time.');
|
||||
$job = new JobCsvSalarieReader();
|
||||
$job->console = $this;
|
||||
$job->handle();
|
||||
$this->info('Job completed');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Command Name: LDC Web Status Checker
|
||||
* Description: Envoi des infos Serveur/Laravel vers LDC Web
|
||||
* Version: 1.0
|
||||
* Author: Vincent BRIDIER
|
||||
* Author URI: vincent.bridier@ldc.fr
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class LDCWebStatusChecker extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ldcweb:statuschecker';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Envoi des infos Serveur/Laravel vers LDC Web';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$data = [];
|
||||
$data['uuid'] = config('ldcweb.project_uuid');
|
||||
|
||||
// Sitemap.xml ?
|
||||
if (file_exists(public_path() . '/sitemap.xml')) {
|
||||
$data['sitemap'] = 'true';
|
||||
} else {
|
||||
$data['sitemap'] = 'false';
|
||||
}
|
||||
|
||||
// Robots.txt ?
|
||||
if (file_exists(public_path() . '/robots.txt')) {
|
||||
$data['robots'] = 'true';
|
||||
} else {
|
||||
$data['robots'] = 'false';
|
||||
}
|
||||
|
||||
// Check logs.
|
||||
$data['logs'] = 0;
|
||||
$patherror = storage_path('/logs');
|
||||
$files = glob($patherror . '/*.log');
|
||||
if (count($files) > 0) {
|
||||
foreach ($files as $file) {
|
||||
$data['logs'] = $data['logs'] + filesize($file);
|
||||
}
|
||||
}
|
||||
|
||||
$data['code']['version'] = app()->version();
|
||||
|
||||
// Send by cURL.
|
||||
$url = 'https://ldc-web.ldc.fr/api/status-checker';
|
||||
$ch = curl_init($url);
|
||||
$payload = ['token' => 'CE8S52Qq7stf5k8frF4T', 'datas' => json_encode($data)];
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\RefreshSiteMap as JobsRefreshSiteMap;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class RefreshSiteMap extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'sitemap:refresh';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Run the RefreshSiteMapJob manually';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Running the Job, this could take some time.');
|
||||
$job = new JobsRefreshSiteMap();
|
||||
$job->console = $this;
|
||||
$job->handle();
|
||||
$this->info('Job completed');
|
||||
}
|
||||
}
|
||||
51
app/Console/Commands/SyncThemeSettings.php
Normal file
51
app/Console/Commands/SyncThemeSettings.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\GeneralConfigType;
|
||||
use App\Models\Site\GeneralConfig;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
class SyncThemeSettings extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'config:sync_theme';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronize theme config with database.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// * Force config clearance.
|
||||
Artisan::call('config:clear');
|
||||
|
||||
// * Force cache to be cleared ( reload GeneralConfigs )
|
||||
Artisan::call('cache:clear');
|
||||
|
||||
// * Fetch or create theme config
|
||||
/** @var \App\Models\Site\GeneralConfig */
|
||||
$config = GeneralConfig::query()->where('type', GeneralConfigType::theme())->firstOrNew();
|
||||
|
||||
// * Fetch Bo Theme Settings.
|
||||
$data = config('theme.bo_theme_settings');
|
||||
|
||||
$config->data = $data;
|
||||
$config->saveOrFail();
|
||||
|
||||
$this->info('Theme config is overrided with the latest theme.config.php content.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\Payment\SystempayCreditTransactionUpdate;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class SystempayCreditTransactionUpdateCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'systempay:update_credit_transactions';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Update Systempay credit transaction statuses';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return inteager
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
\dispatch_sync(new SystempayCreditTransactionUpdate());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,15 @@
|
|||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\DeleteOlds\DeleteOldCollectionException;
|
||||
use App\Jobs\DeleteOlds\DeleteOldCustomers;
|
||||
use App\Jobs\DeleteOlds\DeleteOldOrders;
|
||||
use App\Jobs\DeleteOlds\DeleteOldTimeslots;
|
||||
use App\Jobs\DiscountsStatusUpdate;
|
||||
use App\Jobs\Payment\SystempayCreditTransactionUpdate;
|
||||
use App\Jobs\ProductsOrderableUpdate;
|
||||
use App\Jobs\ProductsStatusUpdate;
|
||||
use App\Jobs\SlidesStatusUpdate;
|
||||
use App\Jobs\XmlIncoReader as JobsXmlIncoReader;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
|
@ -13,8 +22,7 @@ class Kernel extends ConsoleKernel
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
];
|
||||
protected $commands = [];
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
|
|
@ -24,9 +32,21 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// * Update models planified booleans changes
|
||||
$schedule->job(SlidesStatusUpdate::class)->everyMinute();
|
||||
$schedule->job(ProductsStatusUpdate::class)->everyMinute();
|
||||
$schedule->job(ProductsOrderableUpdate::class)->everyMinute();
|
||||
$schedule->job(DiscountsStatusUpdate::class)->everyMinute();
|
||||
$schedule->job(DeleteOldTimeslots::class)->everyMinute();
|
||||
$schedule->command('model:prune')->everyMinute();
|
||||
|
||||
$schedule->command('sitemap:refresh')->dailyAt('16:13');
|
||||
$schedule->command('ldcweb:statuschecker')->everyFifteenMinutes();
|
||||
$schedule->job(JobsXmlIncoReader::class)->name('xml-inco-reader')->onOneServer()->dailyAt('15:00');
|
||||
|
||||
$schedule->job(DeleteOldCustomers::class)->dailyAt('22:50');
|
||||
$schedule->job(DeleteOldOrders::class)->dailyAt('23:00');
|
||||
$schedule->job(DeleteOldCollectionException::class)->dailyAt('10:42');
|
||||
$schedule->job(SystempayCreditTransactionUpdate::class)->dailyAt('03:00');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
79
app/Enums/Discount/DiscountType.php
Normal file
79
app/Enums/Discount/DiscountType.php
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Discount;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self amount()
|
||||
* @method static self percent()
|
||||
*/
|
||||
final class DiscountType extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'amount' => 0,
|
||||
'percent' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'amount' => trans('Montant'),
|
||||
'percent' => trans('Pourcentage'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum units
|
||||
*
|
||||
* @return array<float>
|
||||
*/
|
||||
protected static function units(): array
|
||||
{
|
||||
return [
|
||||
'amount' => '€',
|
||||
'percent' => '%'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum steps
|
||||
*
|
||||
* @return array<float>
|
||||
*/
|
||||
protected static function steps(): array
|
||||
{
|
||||
return [
|
||||
'amount' => 0.01,
|
||||
'percent' => 1
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @return integer|string
|
||||
*/
|
||||
public function __get(string $attribute)
|
||||
{
|
||||
if ($attribute === 'unit') {
|
||||
return $this->units()[$this->getDefinition()] ?? null;
|
||||
}
|
||||
if ($attribute === 'step') {
|
||||
return $this->steps()[$this->getDefinition()] ?? null;
|
||||
}
|
||||
return parent::__get($attribute);
|
||||
}
|
||||
}
|
||||
41
app/Enums/GeneralConfigType.php
Normal file
41
app/Enums/GeneralConfigType.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self global()
|
||||
* @method static self orders()
|
||||
* @method static self theme()
|
||||
*/
|
||||
final class GeneralConfigType extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'global' => 1,
|
||||
'orders' => 2,
|
||||
'theme' => 3,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'global' => __('Configuration du site'),
|
||||
'orders' => __('Configuration des commandes'),
|
||||
'theme' => __('Configuration du theme'),
|
||||
];
|
||||
}
|
||||
}
|
||||
50
app/Enums/InputType.php
Normal file
50
app/Enums/InputType.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self boolean()
|
||||
* @method static self image()
|
||||
* @method static self string()
|
||||
* @method static self password()
|
||||
* @method static self text()
|
||||
* html autorisé
|
||||
* @method static self url()
|
||||
* @method static self imageArray()
|
||||
* @method static self labelArray()
|
||||
* @method static self dropdownArray()
|
||||
* html autorisé
|
||||
* @method static self miniblocArray()
|
||||
* html autorisé
|
||||
* @method static self videoVimeo()
|
||||
* @method static self number()
|
||||
* @method static self email()
|
||||
*/
|
||||
final class InputType extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'boolean' => 0,
|
||||
'image' => 1,
|
||||
'string' => 2,
|
||||
'text' => 3,
|
||||
'url' => 4,
|
||||
'imageArray' => 5,
|
||||
'labelArray' => 6,
|
||||
'dropdownArray' => 7,
|
||||
'miniblocArray' => 8,
|
||||
'videoVimeo' => 9,
|
||||
'number' => 10,
|
||||
'email' => 11,
|
||||
'password' => 12
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self pce()
|
||||
* @method static self kgm()
|
||||
* @method static self colis()
|
||||
*/
|
||||
final class InvoicingUnit extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'pce' => 'PCE',
|
||||
'kgm' => 'KGM',
|
||||
'colis' => 'COLIS',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'pce' => __('Pièce'),
|
||||
'kgm' => __('Kg'),
|
||||
'colis' => __('Colis'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the value as a string
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->label;
|
||||
}
|
||||
}
|
||||
35
app/Enums/Order/DeliveryModeEnum.php
Normal file
35
app/Enums/Order/DeliveryModeEnum.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self inShop()
|
||||
*/
|
||||
final class DeliveryModeEnum extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'inShop' => 1
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'inShop' => __('À la boutique')
|
||||
];
|
||||
}
|
||||
}
|
||||
52
app/Enums/Order/DeliveryStatus.php
Normal file
52
app/Enums/Order/DeliveryStatus.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self pending()
|
||||
* Aucune action n'a été entreprise.
|
||||
* @method static self preparation()
|
||||
* La commande est en préparation
|
||||
* @method static self ready()
|
||||
* La commande est prête a être récupérée
|
||||
* @method static self recovered()
|
||||
* La commande à été récupérée par le client
|
||||
* @method static self canceled()
|
||||
* La commande à été annulée
|
||||
*/
|
||||
final class DeliveryStatus extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'pending' => 0,
|
||||
'preparation' => 1,
|
||||
'ready' => 2,
|
||||
'recovered' => 3,
|
||||
'canceled' => 4
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'pending' => __('À faire'),
|
||||
'preparation' => __('En préparation'),
|
||||
'ready' => __('Prête à être récupérée'),
|
||||
'recovered' => __('Récupérée'),
|
||||
'canceled' => __('Annulée')
|
||||
];
|
||||
}
|
||||
}
|
||||
44
app/Enums/Order/OrderProcess.php
Normal file
44
app/Enums/Order/OrderProcess.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self reviewBasket()
|
||||
* @method static self shippingMethod()
|
||||
* @method static self shippment()
|
||||
* @method static self paymentReview()
|
||||
*/
|
||||
final class OrderProcess extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'reviewBasket' => 0,
|
||||
'shippingMethod' => 1,
|
||||
'shippment' => 2,
|
||||
'paymentReview' => 3
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'reviewBasket' => trans('Panier'),
|
||||
'shippingMethod' => trans('Expédition - mode'),
|
||||
'shippment' => trans('Expédition - détails'),
|
||||
'paymentReview' => trans('Paiement')
|
||||
];
|
||||
}
|
||||
}
|
||||
117
app/Enums/Order/PaymentModeEnum.php
Normal file
117
app/Enums/Order/PaymentModeEnum.php
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use App\Lib\Payments\Adapters\InShopPaymentAdapter;
|
||||
use App\Lib\Payments\Adapters\StripePaymentAdapter;
|
||||
use App\Lib\Payments\Adapters\SystemPayPaymentAdapter;
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self inShop()
|
||||
* Payment in the selected shop when retriving the order
|
||||
* @method static self stripe()
|
||||
* Payment using Stripe services
|
||||
* @method static self systemPay()
|
||||
* Payment using SystemPay services
|
||||
*
|
||||
* @property-read string $adapter The adpater (\App\Lib\Payments\PaymentAdapter) to use for the payment mode.
|
||||
* @property-read integer $minAmount The minimal amount to use the payment mode in cents.
|
||||
* @property-read string $endpoint The host endpoint for the payment mode.
|
||||
*/
|
||||
final class PaymentModeEnum extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'inShop' => 1,
|
||||
'stripe' => 2,
|
||||
'systemPay' => 3
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'inShop' => __('Au magasin'),
|
||||
'stripe' => __('Stripe'),
|
||||
'systemPay' => __('SystemPay')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum rates
|
||||
*
|
||||
* @return array<\App\Lib\Payments\PaymentAdapter>
|
||||
*/
|
||||
protected static function adapterClasses(): array
|
||||
{
|
||||
return [
|
||||
'inShop' => InShopPaymentAdapter::class,
|
||||
'stripe' => StripePaymentAdapter::class,
|
||||
'systemPay' => SystemPayPaymentAdapter::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum minimal amounts in cents
|
||||
*
|
||||
* TODO: Set min amounts (and max) in settings.
|
||||
*
|
||||
* @return array<\App\Lib\Payments\PaymentAdapter>
|
||||
*/
|
||||
protected static function minAmount(): array
|
||||
{
|
||||
return [
|
||||
'inShop' => 0,
|
||||
// * 50 cents
|
||||
'stripe' => 50,
|
||||
// * 1 euro
|
||||
'systemPay' => 100,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum payment modes endpoints
|
||||
*
|
||||
* This is to allow in cors in App Service Provider
|
||||
*
|
||||
* @return array<\App\Lib\Payments\PaymentAdapter>
|
||||
*/
|
||||
protected static function endpoints(): array
|
||||
{
|
||||
return [
|
||||
'inShop' => \parse_url(\config('app.url'), \PHP_URL_HOST),
|
||||
'stripe' => 'stripe.fr',
|
||||
'systemPay' => 'systempay.fr'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @return integer|string
|
||||
*/
|
||||
public function __get(string $attribute)
|
||||
{
|
||||
if ($attribute === 'adapter') {
|
||||
return $this->adapterClasses()[$this->getDefinition()];
|
||||
}
|
||||
if ($attribute === 'minAmount') {
|
||||
return $this->minAmount()[$this->getDefinition()];
|
||||
}
|
||||
if ($attribute === 'endpoint') {
|
||||
return $this->endpoints()[$this->getDefinition()];
|
||||
}
|
||||
return parent::__get($attribute);
|
||||
}
|
||||
}
|
||||
56
app/Enums/Order/PaymentStatus.php
Normal file
56
app/Enums/Order/PaymentStatus.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self pending()
|
||||
* Payment en attente
|
||||
* @method static self failed()
|
||||
* Payment à échoué
|
||||
* @method static self payed()
|
||||
* Le règlement à bien été validé
|
||||
* @method static self refundedPartial()
|
||||
* Le règlement à été remboursé partiellement
|
||||
* @method static self refunded()
|
||||
* Le règlement à été remboursé complétement
|
||||
* @method static self canceled()
|
||||
* Le règlement à été annulé
|
||||
*/
|
||||
final class PaymentStatus extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'pending' => 0,
|
||||
'failed' => 1,
|
||||
'payed' => 3,
|
||||
'refundedPartial' => 4,
|
||||
'refunded' => 5,
|
||||
'canceled' => 6
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'pending' => __('En attente'),
|
||||
'failed' => __('Échec'),
|
||||
'payed' => __('Réglée'),
|
||||
'refundedPartial' => __('Remboursé partiellement'),
|
||||
'refunded' => __('Remboursé complètement'),
|
||||
'canceled' => __('Annulée'),
|
||||
];
|
||||
}
|
||||
}
|
||||
48
app/Enums/Order/TransactionStatus.php
Normal file
48
app/Enums/Order/TransactionStatus.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self pending()
|
||||
* Transaction en cours
|
||||
* @method static self failed()
|
||||
* Transaction à échoué
|
||||
* @method static self validated()
|
||||
* Transaction est validée
|
||||
* @method static self canceled()
|
||||
* Transaction est anluléee
|
||||
*/
|
||||
final class TransactionStatus extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'pending' => 0,
|
||||
'failed' => 1,
|
||||
'validated' => 2,
|
||||
'canceled' => 3
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'pending' => __('En attente'),
|
||||
'failed' => __('Échec'),
|
||||
'validated' => __('Validée'),
|
||||
'canceled' => __('Annulée')
|
||||
];
|
||||
}
|
||||
}
|
||||
40
app/Enums/Order/TransactionType.php
Normal file
40
app/Enums/Order/TransactionType.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self debit()
|
||||
* Mouvement d'une transaction du client vers la boutique
|
||||
* @method static self credit()
|
||||
* Mouvement d'une transaction de la boutique vers le client
|
||||
*/
|
||||
final class TransactionType extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'debit' => 0,
|
||||
'credit' => 1
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'debit' => __('Débit'),
|
||||
'credit' => __('Crédit')
|
||||
];
|
||||
}
|
||||
}
|
||||
44
app/Enums/Order/ValidationStatus.php
Normal file
44
app/Enums/Order/ValidationStatus.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Order;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self pending()
|
||||
* La commande n'est pas encore évaluée
|
||||
* @method static self canceled()
|
||||
* La commande est annulée
|
||||
* @method static self validated()
|
||||
* La commande est validée (pour préparation)
|
||||
*/
|
||||
final class ValidationStatus extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'pending' => 0,
|
||||
'canceled' => 1,
|
||||
'validated' => 2,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'pending' => __('En attente de validation'),
|
||||
'canceled' => __('Annulée'),
|
||||
'validated' => __('Validée'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self pce()
|
||||
* @method static self kgm()
|
||||
* @method static self colis()
|
||||
*/
|
||||
final class OrderUnit extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'pce' => 'PCE',
|
||||
'kgm' => 'KGM',
|
||||
'colis' => 'COLIS',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'pce' => __('Pièce'),
|
||||
'kgm' => __('Kg'),
|
||||
'colis' => __('Colis'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the value as a string
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->label;
|
||||
}
|
||||
}
|
||||
80
app/Enums/Product/DefaultProductType.php
Normal file
80
app/Enums/Product/DefaultProductType.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Product;
|
||||
|
||||
use App\Enums\InputType;
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self default()
|
||||
* @method static self inco()
|
||||
*/
|
||||
final class DefaultProductType extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'default' => 'De base',
|
||||
'inco' => 'Alimentaire lié a Inco',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Inco minicrud inputs for specific product type inco
|
||||
* ! Attention toute modification après la mise en
|
||||
* ! production doit faire l'objet d'une migration
|
||||
* ! pour réaligner le contenu du champ data
|
||||
* ! pour chaque type de produit
|
||||
* ! sous peine de de tout casser
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function incoInputs(): array
|
||||
{
|
||||
return [
|
||||
'ingredients' => [
|
||||
'label' => 'Ingrédients',
|
||||
'inputType' => InputType::text(),
|
||||
'text' => '',
|
||||
'validate' => 'nullable|string'
|
||||
],
|
||||
'preparation_advices' => [
|
||||
'label' => 'Conseils de préparation',
|
||||
'inputType' => InputType::text(),
|
||||
'text' => '',
|
||||
'validate' => 'nullable|string'
|
||||
],
|
||||
'allergens' => [
|
||||
'label' => 'Ingrédients allèrgenes',
|
||||
'inputType' => InputType::text(),
|
||||
'text' => '',
|
||||
'validate' => 'nullable|string'
|
||||
],
|
||||
'selling_arguments' => [
|
||||
'label' => 'Arguments de vente',
|
||||
'inputType' => InputType::text(),
|
||||
'text' => '',
|
||||
'validate' => 'nullable|string'
|
||||
],
|
||||
'servings' => [
|
||||
'label' => 'Portions',
|
||||
'inputType' => InputType::string(),
|
||||
'value' => '',
|
||||
'required' => false,
|
||||
'validate' => 'nullable|string|max:35'
|
||||
],
|
||||
'servings_type' => [
|
||||
'label' => 'Type de portions',
|
||||
'inputType' => InputType::string(),
|
||||
'value' => '',
|
||||
'required' => false,
|
||||
'validate' => 'nullable|string|max:150'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
namespace App\Enums\Product;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
71
app/Enums/Product/TaxRate.php
Normal file
71
app/Enums/Product/TaxRate.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Product;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* Calcul par unité de produits
|
||||
*
|
||||
* @method static self twenty()
|
||||
* @method static self ten()
|
||||
* @method static self five()
|
||||
*
|
||||
* @property-read float $rate The TVA rate.
|
||||
*/
|
||||
final class TaxRate extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'twenty' => 0,
|
||||
'ten' => 1,
|
||||
'five' => 2
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'twenty' => trans('Taux normal'),
|
||||
'ten' => trans('Taux reduit'),
|
||||
'five' => trans('Taux très reduit')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum rates
|
||||
*
|
||||
* @return array<float>
|
||||
*/
|
||||
protected static function rates(): array
|
||||
{
|
||||
return [
|
||||
'twenty' => 20,
|
||||
'ten' => 10,
|
||||
'five' => 5.5,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @return integer|string
|
||||
*/
|
||||
public function __get(string $attribute)
|
||||
{
|
||||
if ($attribute === 'rate') {
|
||||
return $this->rates()[$this->getDefinition()] ?? null;
|
||||
}
|
||||
return parent::__get($attribute);
|
||||
}
|
||||
}
|
||||
104
app/Enums/Product/WeightUnit.php
Normal file
104
app/Enums/Product/WeightUnit.php
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Product;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self g()
|
||||
* @method static self kg()
|
||||
* @method static self ton()
|
||||
*/
|
||||
final class WeightUnit extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'g' => 'G',
|
||||
'kg' => 'KG',
|
||||
'ton' => 'T',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'g' => __('g'),
|
||||
'kg' => __('kg'),
|
||||
'ton' => __('t'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum conversions a partir de gramme
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function conversions(): array
|
||||
{
|
||||
return [
|
||||
'g' => 1,
|
||||
'kg' => 1000,
|
||||
'ton' => 1000000,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @return integer|string
|
||||
*/
|
||||
public function __get(string $attribute)
|
||||
{
|
||||
if ($attribute === 'conversion') {
|
||||
return $this->conversions()[$this->getDefinition()] ?? null;
|
||||
}
|
||||
return parent::__get($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format weight into a displayable unit.
|
||||
* @param integer $weightG The weight in grams.
|
||||
* @param \App\Enums\WeightUnit|null $forceUnit To force specific unit display.
|
||||
* @return string
|
||||
*/
|
||||
public static function getDisplayableWeight(int $weightG, self $forceUnit = null): string
|
||||
{
|
||||
if ($forceUnit) {
|
||||
number_format(round($weightG / $forceUnit->conversion, 2), 2, ',', '') . $forceUnit->label;
|
||||
}
|
||||
$displayable = self::convertWeightToAdequatUnit($weightG);
|
||||
return \number_format($displayable->value, 2, ',', '') . ' ' . $displayable->enum->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert value to the adequat unit
|
||||
* @param integer $weightG The weight in grams.
|
||||
* @return object<'enum'|'value',self>
|
||||
*/
|
||||
private static function convertWeightToAdequatUnit(int $weightG): object
|
||||
{
|
||||
foreach (self::conversions() as $key => $conversionRate) {
|
||||
$convertedTest = round($weightG / $conversionRate, 2);
|
||||
if ($convertedTest > 0.001 and $convertedTest <= 1000) {
|
||||
return (object)[
|
||||
'enum' => self::make($key),
|
||||
'value' => $convertedTest
|
||||
];
|
||||
}
|
||||
}
|
||||
return (object)[
|
||||
'enum' => \collect(self::toArray())->last(),
|
||||
'value' => $weightG
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self public()
|
||||
* @method static self salaries()
|
||||
*/
|
||||
final class SettingRegisterMode extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'public' => 'public',
|
||||
'salaries' => 'salaries',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'public' => __('Public'),
|
||||
'salaries' => __('Salaries'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the value as a string
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->label;
|
||||
}
|
||||
}
|
||||
60
app/Enums/StaticPageType.php
Normal file
60
app/Enums/StaticPageType.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self home()
|
||||
* Page d'accueil
|
||||
* @method static self contact()
|
||||
* Page de contact
|
||||
* @method static self legals()
|
||||
* Page mentions légales
|
||||
* @method static self sellconditions()
|
||||
* Page conditions de ventes
|
||||
* @method static self confidentiality()
|
||||
* Page politique de confidentialitée
|
||||
* @method static self faq()
|
||||
* Page faq
|
||||
* @method static self crud()
|
||||
* Page de contenus libre en CRUD.
|
||||
*/
|
||||
final class StaticPageType extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'home' => 0,
|
||||
'contact' => 1,
|
||||
'legals' => 2,
|
||||
'sellconditions' => 3,
|
||||
'confidentiality' => 4,
|
||||
'faq' => 5,
|
||||
'crud' => 6
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'home' => trans('Accueil'),
|
||||
'contact' => trans('Contact'),
|
||||
'legals' => trans('Mentions Légales'),
|
||||
'sellconditions' => trans('CGV'),
|
||||
'confidentiality' => trans('Politique de confidentialité'),
|
||||
'faq' => trans('FAQ'),
|
||||
'crud' => trans('Pages libres'),
|
||||
];
|
||||
}
|
||||
}
|
||||
14
app/Enums/Stripe/CheckoutPaymentStatus.php
Normal file
14
app/Enums/Stripe/CheckoutPaymentStatus.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Stripe;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self paid()
|
||||
* @method static self unpaid()
|
||||
* @method static self no_payment_required()
|
||||
*/
|
||||
final class CheckoutPaymentStatus extends BaseEnum
|
||||
{
|
||||
}
|
||||
53
app/Enums/TimeSlot/WeekDay.php
Normal file
53
app/Enums/TimeSlot/WeekDay.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\TimeSlot;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self monday()
|
||||
* @method static self tuesday()
|
||||
* @method static self wednesday()
|
||||
* @method static self thursday()
|
||||
* @method static self friday()
|
||||
* @method static self saturday()
|
||||
* @method static self sunday()
|
||||
*/
|
||||
final class WeekDay extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'monday' => 1,
|
||||
'tuesday' => 2,
|
||||
'wednesday' => 3,
|
||||
'thursday' => 4,
|
||||
'friday' => 5,
|
||||
'saturday' => 6,
|
||||
'sunday' => 7,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'monday' => trans('Lundi'),
|
||||
'tuesday' => trans('Mardi'),
|
||||
'wednesday' => trans('Mercredi'),
|
||||
'thursday' => trans('Jeudi'),
|
||||
'friday' => trans('Vendredi'),
|
||||
'saturday' => trans('Samedi'),
|
||||
'sunday' => trans('Dimanche')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -5,14 +5,10 @@ namespace App\Enums;
|
|||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* This is an enumeration class,
|
||||
* the following methods are its possible values
|
||||
*
|
||||
* @method static self authenticated()
|
||||
* @method static self guest()
|
||||
*
|
||||
* @method static self admin()
|
||||
* @method static self user()
|
||||
*/
|
||||
class PriceShowingMode extends BaseEnumRoutable
|
||||
final class UserRole extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
|
|
@ -22,8 +18,8 @@ class PriceShowingMode extends BaseEnumRoutable
|
|||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'authenticated' => 'authenticated',
|
||||
'guest' => 'guest',
|
||||
'admin' => 1,
|
||||
'user' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -35,8 +31,8 @@ class PriceShowingMode extends BaseEnumRoutable
|
|||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'authenticated' => __('Client Connecté'),
|
||||
'guest' => __('Public'),
|
||||
'admin' => trans('Administrateur'),
|
||||
'user' => trans('Utilisateur'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self g()
|
||||
* @method static self kg()
|
||||
* @method static self ton()
|
||||
*/
|
||||
final class WeightUnit extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'g' => 'G',
|
||||
'kg' => 'KG',
|
||||
'ton' => 'T',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'g' => __('Gramme'),
|
||||
'kg' => __('Kg'),
|
||||
'ton' => __('Tonne'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* conversion values
|
||||
* base kg()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function convert(): array
|
||||
{
|
||||
return [
|
||||
'G' => 0.001,
|
||||
'KG' => 1,
|
||||
'T' => 1000,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the value as a string
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->label;
|
||||
}
|
||||
}
|
||||
37
app/Events/OrderIsCreated.php
Normal file
37
app/Events/OrderIsCreated.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Shop\Order;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class OrderIsCreated
|
||||
{
|
||||
use Dispatchable;
|
||||
use SerializesModels;
|
||||
|
||||
/** @var \App\Models\Shop\Order */
|
||||
private $order;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Order $order)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Event order
|
||||
*
|
||||
* @return \App\Models\Shop\Order
|
||||
*/
|
||||
public function getOrder(): Order
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
}
|
||||
53
app/Events/OrderIsPaid.php
Normal file
53
app/Events/OrderIsPaid.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Payment\Transaction;
|
||||
use App\Models\Shop\Order;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class OrderIsPaid
|
||||
{
|
||||
use Dispatchable;
|
||||
use SerializesModels;
|
||||
|
||||
/** @var \App\Models\Shop\Order */
|
||||
private $order;
|
||||
|
||||
/** @var \App\Models\Payment\Transaction */
|
||||
private $transaction;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @param \App\Models\Payment\Transaction $transaction
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Order $order, Transaction $transaction)
|
||||
{
|
||||
$this->order = $order;
|
||||
$this->transaction = $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Event order
|
||||
*
|
||||
* @return \App\Models\Shop\Order
|
||||
*/
|
||||
public function getOrder(): Order
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Event transaction
|
||||
*
|
||||
* @return \App\Models\Payment\Transaction
|
||||
*/
|
||||
public function getTransaction(): Transaction
|
||||
{
|
||||
return $this->transaction;
|
||||
}
|
||||
}
|
||||
53
app/Events/OrderIsRefunded.php
Normal file
53
app/Events/OrderIsRefunded.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Payment\Transaction;
|
||||
use App\Models\Shop\Order;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class OrderIsRefunded
|
||||
{
|
||||
use Dispatchable;
|
||||
use SerializesModels;
|
||||
|
||||
/** @var \App\Models\Shop\Order */
|
||||
private $order;
|
||||
|
||||
/** @var \App\Models\Payment\Transaction */
|
||||
private $transaction;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order The order to refund.
|
||||
* @param \App\Models\Payment\Transaction $transaction The transaction concerned by the refund.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Order $order, Transaction $transaction)
|
||||
{
|
||||
$this->order = $order;
|
||||
$this->transaction = $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Event order
|
||||
*
|
||||
* @return \App\Models\Shop\Order
|
||||
*/
|
||||
public function getOrder(): Order
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Event transaction
|
||||
*
|
||||
* @return \App\Models\Payment\Transaction
|
||||
*/
|
||||
public function getTransaction(): Transaction
|
||||
{
|
||||
return $this->transaction;
|
||||
}
|
||||
}
|
||||
37
app/Events/OrderIsValidated.php
Normal file
37
app/Events/OrderIsValidated.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Shop\Order;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class OrderIsValidated
|
||||
{
|
||||
use Dispatchable;
|
||||
use SerializesModels;
|
||||
|
||||
/** @var \App\Models\Shop\Order */
|
||||
private $order;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Order $order)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Event order
|
||||
*
|
||||
* @return \App\Models\Shop\Order
|
||||
*/
|
||||
public function getOrder(): Order
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,23 +3,20 @@
|
|||
namespace App\Exceptions;
|
||||
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* A list of the exception types that are not reported.
|
||||
*
|
||||
* @var array
|
||||
* @var array<int,class-string<Throwable>>
|
||||
*/
|
||||
protected $dontReport = [];
|
||||
|
||||
/**
|
||||
* A list of the inputs that are never flashed for validation exceptions.
|
||||
*
|
||||
* @var array
|
||||
* @var array<int,string>
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'password',
|
||||
|
|
@ -33,65 +30,10 @@ class Handler extends ExceptionHandler
|
|||
*/
|
||||
public function register()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unauthenticated as exception
|
||||
*
|
||||
* @param mixed $request
|
||||
* @param AuthenticationException $exception
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function unauthenticated($request, AuthenticationException $exception)
|
||||
{
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['error' => 'Unauthenticated.'], 401);
|
||||
}
|
||||
$guard = $exception->guards()[0];
|
||||
switch ($guard) {
|
||||
case 'customer':
|
||||
$login = 'auth.connexion';
|
||||
break;
|
||||
default:
|
||||
$login = 'auth.login';
|
||||
break;
|
||||
}
|
||||
// Cf. issue :
|
||||
// Https://stackoverflow.com/questions/52417438/laravel-unauthenticated-redirect-issue-with-multiple-authentication.
|
||||
// Session::forget('url.intented'); .
|
||||
return redirect()->guest(route($login));
|
||||
}
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
*
|
||||
* @param \Throwable $e
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $e)
|
||||
{
|
||||
if (get_class($e) == RedirectTo::class) {
|
||||
abort(redirect($e->url));
|
||||
}
|
||||
|
||||
if (config('app.debug') === false) {
|
||||
if ($this->shouldntReport($e)) {
|
||||
return;
|
||||
$this->reportable(function (\Throwable $e) {
|
||||
if (app()->bound('sentry')) {
|
||||
app('sentry')->captureException($e);
|
||||
}
|
||||
Mail::send([
|
||||
'html' => 'emails.exception',
|
||||
'text' => 'emails.exception-plain'
|
||||
], [
|
||||
'exception' => $e,
|
||||
'appName' => config('app.name')
|
||||
], function ($m) {
|
||||
$m->to(
|
||||
config('mail.contactsList.serviceweb'),
|
||||
sprintf('%s Exception Handler', config('app.name'))
|
||||
)->subject('Need help !, an error occured in your application, please check Logs ASAP');
|
||||
});
|
||||
}
|
||||
|
||||
parent::report($e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display login form
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
return view('auth.login-bo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute login form
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required',
|
||||
'password' => 'required'
|
||||
]);
|
||||
|
||||
$credentials = $request->only(['email', 'password']);
|
||||
|
||||
if (Auth::attempt($credentials)) {
|
||||
$user = Auth::user();
|
||||
if ($user->role === 1 || $user->role === 2) {
|
||||
return redirect()->route('bo.dashboard');
|
||||
} else {
|
||||
if ($user->email_verified_at === null) {
|
||||
Auth::logout();
|
||||
return view('auth.login')->withErrors('Compte non activé.');
|
||||
}
|
||||
return redirect()->intended('/');
|
||||
}
|
||||
}
|
||||
return view('auth.login')->withErrors('Informations incorrectes.');
|
||||
}
|
||||
|
||||
/**
|
||||
* logout
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
Auth::logout();
|
||||
return redirect()->route('home');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display register form
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
return view('auth.register');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute regioster form
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
*/
|
||||
public function register(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'lastname' => 'required|string|max:255',
|
||||
'firstname' => 'required|string|max:255',
|
||||
'date_of_birth' => 'required|date|before_or_equal:' . Carbon::now()->subYears(18)->toDateString(),
|
||||
'email' => 'required|string|email|max:255|unique:users|confirmed',
|
||||
'password' => 'required|string|min:8',
|
||||
]);
|
||||
|
||||
User::create([
|
||||
'firstname' => $request->firstname,
|
||||
'lastname' => $request->lastname,
|
||||
'date_of_birth' => $request->date_of_birth,
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
'role' => 3
|
||||
]);
|
||||
|
||||
// Envoi mail activation.
|
||||
return redirect()->route('auth.register')->with('success', 'Mail envoyé pour confirmation');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display reset password form
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
return view('auth.reset-password');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Gloudemans\Shoppingcart\Facades\Cart;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class BasketController extends Controller
|
||||
{
|
||||
/**
|
||||
* ajout de produit au panier
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function addToCart(Request $request)
|
||||
{
|
||||
$instance = $request->instance ?? "panier";
|
||||
$product = Product::find($request->id);
|
||||
Cart::instance($instance);
|
||||
Cart::add($product, $request->qty);
|
||||
return $this->getCart($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* ajout de plusieurs produits au panier
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function addToCartLot(Request $request)
|
||||
{
|
||||
$instance = $request->instance ?? "panier";
|
||||
Cart::instance($instance);
|
||||
$lot = $request->items;
|
||||
foreach ($lot as $item) {
|
||||
$product = Product::find($item["cartItem"]["id"]);
|
||||
Cart::add($product, $item["cartItem"]["qty"]);
|
||||
}
|
||||
return $this->getCart($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* suppression de produit du panier
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function removeFromCart(Request $request)
|
||||
{
|
||||
$instance = $request->instance ?? "panier";
|
||||
$rowId = $request->rowId;
|
||||
Cart::instance($instance);
|
||||
Cart::remove($rowId);
|
||||
return $this->getCart($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* vidage de panier
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function emptyCart(Request $request)
|
||||
{
|
||||
$instance = $request->instance ?? "panier";
|
||||
Cart::instance($instance);
|
||||
Cart::destroy();
|
||||
return $this->getCart($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* récupération du panier
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCartRequest(Request $request)
|
||||
{
|
||||
$instance = $request->instance ?? "panier";
|
||||
Cart::instance($instance);
|
||||
return $this->getCart($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* return cart data array
|
||||
*
|
||||
* @param string $instance
|
||||
* @return array
|
||||
*/
|
||||
public function getCart(string $instance = "panier")
|
||||
{
|
||||
Cart::instance($instance);
|
||||
$dbpanier = new Collection();
|
||||
foreach (Cart::content() as $row) {
|
||||
$product = $row->model;
|
||||
|
||||
$product->calculatedPrices = $product->getCalcPrices();
|
||||
|
||||
$row->setTaxRate($product->tax->rate);
|
||||
$row->setDiscountRate($product->discountRate);
|
||||
|
||||
$cartextendedItem = array(
|
||||
'cartItem' => $row,
|
||||
'product' => $product
|
||||
);
|
||||
$dbpanier->add($cartextendedItem);
|
||||
}
|
||||
|
||||
$cartInfos = array(
|
||||
"totalTTC" => Cart::total(),
|
||||
// Total des taxes.
|
||||
'totalTVA' => Cart::tax(),
|
||||
// Total sans les taxes.
|
||||
'totalHT' => Cart::subtotal(),
|
||||
// Poids total des items.
|
||||
'totalweight' => Cart::weight(),
|
||||
// Total avant taxes et remises.
|
||||
'totalHTbefore' => Cart::priceTotal(),
|
||||
// Total des remises.
|
||||
'totaldiscount' => Cart::discount(),
|
||||
// Nb de produits dans le cart.
|
||||
'countItems' => Cart::count(),
|
||||
);
|
||||
|
||||
$cartInfosNoPrice = array(
|
||||
"totalTTC" => "-.--",
|
||||
// Total des taxes.
|
||||
'totalTVA' => "-.--",
|
||||
// Total sans les taxes.
|
||||
'totalHT' => "-.--",
|
||||
// Poids total des items.
|
||||
'totalweight' => Cart::weight(),
|
||||
// Total avant taxes et remises.
|
||||
'totalHTbefore' => "-.--",
|
||||
// Total des remises.
|
||||
'totaldiscount' => "-.--",
|
||||
// Nb de produits dans le cart.
|
||||
'countItems' => Cart::count(),
|
||||
);
|
||||
|
||||
$cartReturn = array($dbpanier,$cartInfosNoPrice);
|
||||
if (config('bosettings.show_prices_authenticated') == "authenticated") {
|
||||
{
|
||||
if (Auth::guard('customer')->check()) {
|
||||
$cartReturn = array($dbpanier,$cartInfos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config('bosettings.show_prices_guest') == "guest") {
|
||||
$cartReturn = array($dbpanier,$cartInfos);
|
||||
}
|
||||
|
||||
return $cartReturn;
|
||||
}
|
||||
}
|
||||
56
app/Http/Controllers/Bo/Auth/LoginController.php
Normal file
56
app/Http/Controllers/Bo/Auth/LoginController.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
use AuthenticatesUsers;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest:backend')->except('logout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the guard to be used during authentication.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
{
|
||||
return Auth::guard('backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application's login form.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showLoginForm()
|
||||
{
|
||||
return view('back::auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo(): string
|
||||
{
|
||||
$intendedUrl = response()->redirectToIntended()->getTargetUrl();
|
||||
$intendedRequest = Request::create($intendedUrl);
|
||||
return \strpos($intendedRequest->path(), '/ bo') === 0 ?
|
||||
response()->redirectToIntended()->getTargetUrl() :
|
||||
\route('bo.dashboard');
|
||||
}
|
||||
}
|
||||
31
app/Http/Controllers/Bo/Auth/ResetPasswordController.php
Normal file
31
app/Http/Controllers/Bo/Auth/ResetPasswordController.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Get the guard to be used during authentication.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
{
|
||||
return Auth::guard('backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo(): string
|
||||
{
|
||||
return \route('bo.login');
|
||||
}
|
||||
}
|
||||
93
app/Http/Controllers/Bo/ContactMessagesController.php
Normal file
93
app/Http/Controllers/Bo/ContactMessagesController.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Customer\Contact;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContactMessagesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $contactMessages */
|
||||
$contactMessages = Contact::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$contactMessages,
|
||||
$request->search,
|
||||
null,
|
||||
'order_number',
|
||||
'firstname',
|
||||
'lastname',
|
||||
'subject',
|
||||
'email',
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($contactMessages);
|
||||
$searchFields = trans('N° cmde, Nom, Prénom, Objet, E-mail');
|
||||
|
||||
$contactMessages = $contactMessages->orderBy('done', 'ASC')
|
||||
->orderBy('created_at', 'DESC')->paginate();
|
||||
|
||||
return view('back::pages.contacts.index', compact('contactMessages', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show contact message
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function show(Contact $contact)
|
||||
{
|
||||
return view('back::pages.contacts.show', [
|
||||
'contactMessage' => $contact
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show contact message
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function done(Contact $contact)
|
||||
{
|
||||
$contact->done = true;
|
||||
if ($contact->saveOrFail()) {
|
||||
return response()->redirectToRoute('bo.contacts.index')->with(
|
||||
'bo.success',
|
||||
trans('Le message à été marqué comme traité')
|
||||
);
|
||||
}
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Customer\Contact $contact
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Contact $contact)
|
||||
{
|
||||
if ($contact->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.contacts.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => __('Message de contact')]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Content;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Manage content page
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $key
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
*/
|
||||
public function manage(Request $request, string $key)
|
||||
{
|
||||
$content = Content::where('key', $key)->first();
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$banner = $request->banner;
|
||||
$title = $request->title;
|
||||
$chapeau = $request->chapeau;
|
||||
$maintext = $request->value;
|
||||
|
||||
$request->validate([
|
||||
'banner' => 'image|mimes:jpeg,png,jpg|max:2048|dimensions:max_width=' .
|
||||
config('theme.content_banner_maxwidth') .
|
||||
',max_height=' . config('theme.content_banner_maxheight'),
|
||||
'value' => 'required',
|
||||
]);
|
||||
|
||||
if ($banner !== null) {
|
||||
if ($content->banner !== null && file_exists(public_path('images/content/') . $content->banner)) {
|
||||
unlink(public_path('images/content/') . $content->banner);
|
||||
}
|
||||
$imageName = $content->id . '.' . $banner->extension();
|
||||
$banner->move(public_path('images/content'), $imageName);
|
||||
$content->banner = $imageName;
|
||||
}
|
||||
|
||||
$content->title = $title;
|
||||
$content->chapeau = $chapeau;
|
||||
$content->value = $maintext;
|
||||
$content->save();
|
||||
|
||||
return redirect()->route('bo.content', ['key' => $content->key, 'content' => $content])
|
||||
->with('success', 'Modifications enregistrés !');
|
||||
}//end if
|
||||
|
||||
return view('bo.content.manage', compact('content'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Magasin;
|
||||
use App\Models\TimeslotSetting;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CreneauxController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display creneaux settings form
|
||||
*
|
||||
* @param Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
*/
|
||||
public function settings(Request $request, int $id)
|
||||
{
|
||||
// @phpcs:enable
|
||||
$magasin = Magasin::findOrFail($id);
|
||||
$timeslotSettings = $magasin->timeslotSettings;
|
||||
if ($timeslotSettings->count() === 0) {
|
||||
// Aucun settings pour ce magasin.
|
||||
$timeslotSettings = $this->makeCreneauxSettings($id);
|
||||
}
|
||||
|
||||
return view('bo.creneaux.settings', compact('timeslotSettings', 'magasin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve creneaux settings
|
||||
*
|
||||
* @param integer $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function makeCreneauxSettings(int $id)
|
||||
{
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
$dayset = new TimeslotSetting();
|
||||
$dayset->magasin_id = $id;
|
||||
$dayset->day_index = '' . $i;
|
||||
$dayset->save();
|
||||
}
|
||||
return Magasin::findOrFail($id)->timeslotSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* save settings
|
||||
*
|
||||
* @param Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function updateSettings(Request $request, int $id)
|
||||
{
|
||||
$plage = $request->plage;
|
||||
$magasin_id = $id;
|
||||
|
||||
foreach ($plage as $index => $day) {
|
||||
$setting = TimeslotSetting::where('day_index', '' . $index)
|
||||
->where('magasin_id', $magasin_id)
|
||||
->firstOrFail();
|
||||
// $setting->magasin_id = $magasin_id; ne doit pas changer
|
||||
$setting->morning_start = $day['morning_start'];
|
||||
$setting->morning_end = $day['morning_end'];
|
||||
$setting->afternoon_start = $day['afternoon_start'];
|
||||
$setting->afternoon_end = $day['afternoon_end'];
|
||||
$setting->interval = $day['interval'];
|
||||
$setting->max_orders_per_interval = $day['max_orders_per_interval'];
|
||||
$setting->min_order_preparation = $day['min_order_preparation'];
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
return redirect()->route('bo.creneaux.settings', $magasin_id)->with('success', 'Modifications enregistrées !');
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,6 @@ class DashboardController extends Controller
|
|||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('bo.dashboard');
|
||||
return view('back::pages.dashboard');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
73
app/Http/Controllers/Bo/DeliveryModeController.php
Normal file
73
app/Http/Controllers/Bo/DeliveryModeController.php
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\DeliveryMode\UpdateDeliveryModeRequest;
|
||||
use App\Models\Shop\DeliveryMode;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DeliveryModeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$deliveryModes = DeliveryMode::paginate();
|
||||
|
||||
return view('back::pages.delivery-modes.index', compact('deliveryModes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Shop\DeliveryMode $deliveryMode
|
||||
* @return \Illuminate\Http\Response
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function edit(DeliveryMode $deliveryMode)
|
||||
{
|
||||
$this->authorize('update', DeliveryMode::class);
|
||||
return view('back::pages.delivery-modes.edit', compact(
|
||||
'deliveryMode'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\UpdateDeliveryModeRequest $request
|
||||
* @param \App\Models\Shop\DeliveryMode $deliveryMode
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateDeliveryModeRequest $request, DeliveryMode $deliveryMode)
|
||||
{
|
||||
$this->authorize('update', DeliveryMode::class);
|
||||
$deliveryMode->fill($request->validated());
|
||||
if ($deliveryMode->saveOrFail()) {
|
||||
return redirect()->back()
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.delivery_modes'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change model status
|
||||
*
|
||||
* @param DeliveryMode $model
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function changeStatus(DeliveryMode $model)
|
||||
{
|
||||
$this->authorize('update', DeliveryMode::class);
|
||||
$model->status = !$model->status;
|
||||
$model->saveOrFail();
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
173
app/Http/Controllers/Bo/DiscountController.php
Normal file
173
app/Http/Controllers/Bo/DiscountController.php
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\Discount\DiscountType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Discounts\StoreDiscountRequest;
|
||||
use App\Http\Requests\Bo\Discounts\UpdateDiscountRequest;
|
||||
use App\Models\Shop\Discount;
|
||||
use App\Models\Merchandise\Product;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DiscountController extends Controller
|
||||
{
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $discounts */
|
||||
$discounts = Discount::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$discounts,
|
||||
$request->search,
|
||||
// * Search in ranges
|
||||
function (Builder $q) use ($request) {
|
||||
$types = \collect(DiscountType::toArray())->filter(function (DiscountType $type) use ($request) {
|
||||
$test = Str::contains(
|
||||
Str::lower($type->label),
|
||||
\explode(' ', Str::lower(\trim($request->search)))
|
||||
);
|
||||
return Str::contains(
|
||||
Str::lower($type->label),
|
||||
\explode(' ', Str::lower(\trim($request->search)))
|
||||
);
|
||||
});
|
||||
$q->orWhereIn('type', $types);
|
||||
},
|
||||
'discount_value'
|
||||
);
|
||||
} //end if
|
||||
|
||||
$this->sortQuery($discounts);
|
||||
$searchFields = trans('Type');
|
||||
|
||||
$discounts->orderBy('updated_at', 'DESC');
|
||||
$discounts->with(['products.discount']);
|
||||
$discounts = $discounts->paginate();
|
||||
|
||||
return view('back::pages.discounts.index', compact('discounts', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<mixed,\App\Models\Merchandise\Product> */
|
||||
$existingProds = Product::all();
|
||||
|
||||
return view('back::pages.discounts.create', \compact(
|
||||
'existingProds'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Discounts\StoreDiscountRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreDiscountRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$discount = new Discount();
|
||||
|
||||
$discount->fill($request->validated());
|
||||
|
||||
if ($discount->saveOrFail()) {
|
||||
$discount->associateProducts($request->prods);
|
||||
|
||||
$discount->saveOrFail();
|
||||
return redirect()
|
||||
->route('bo.discounts.edit', $discount)
|
||||
->with('bo.success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.discounts'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Shop\Discount $discount
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Discount $discount)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<mixed,\App\Models\Merchandise\Product> */
|
||||
$selectedProds = $discount->products;
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<mixed,\App\Models\Merchandise\Product> */
|
||||
$existingProds = Product::all();
|
||||
|
||||
return view('back::pages.discounts.edit', [
|
||||
'discountModel' => $discount,
|
||||
'existingProds' => $existingProds,
|
||||
'selectedProds' => $selectedProds
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Discounts\UpdateDiscountRequest $request
|
||||
* @param \App\Models\Shop\Discount $discount
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateDiscountRequest $request, Discount $discount)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $discount) {
|
||||
// * Minicrud fill
|
||||
$discount->fill($request->validated());
|
||||
|
||||
$discount->makeStatusSense();
|
||||
$discount->associateProducts($request->prods);
|
||||
|
||||
if ($discount->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.discounts.edit', $discount)
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.discounts'))]
|
||||
));
|
||||
} //end if
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Shop\Discount $discount
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Discount $discount)
|
||||
{
|
||||
if ($discount->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.discounts.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.discounts'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Faq;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class FaqController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$faq = Faq::all();
|
||||
return view('bo.faq.index', compact('faq'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update faq data.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function saveDatas(Request $request)
|
||||
{
|
||||
$faq = $request->faq;
|
||||
|
||||
$looplimit = count($faq);
|
||||
for ($i = 0; $i < $looplimit; $i++) {
|
||||
$faqToInsert = !empty($faq[$i]["question"]) && !empty($faq[$i]["answer"]);
|
||||
if (isset($faq[$i]["id"]) && $faq[$i]["id"] !== null && $faqToInsert) {
|
||||
$f = Faq::findOrFail($faq[$i]["id"]);
|
||||
$f->question = $faq[$i]["question"];
|
||||
$f->answer = $faq[$i]["answer"];
|
||||
$f->save();
|
||||
} else {
|
||||
if ($faqToInsert) {
|
||||
$c = Faq::updateOrCreate([
|
||||
'question' => $faq[$i]["question"],
|
||||
'answer' => $faq[$i]["answer"]
|
||||
]);
|
||||
$faq[$i]["id"] = $c->id;
|
||||
} else {
|
||||
unset($faq[$i]);
|
||||
$i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $faq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$faq = Faq::findOrFail($request->id);
|
||||
$faq->delete();
|
||||
|
||||
return "Suppression terminée !";
|
||||
}
|
||||
}
|
||||
51
app/Http/Controllers/Bo/GeneralConfigController.php
Normal file
51
app/Http/Controllers/Bo/GeneralConfigController.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\UpdateGeneralConfigRequest;
|
||||
use App\Models\Site\GeneralConfig;
|
||||
|
||||
class GeneralConfigController extends Controller
|
||||
{
|
||||
/**
|
||||
* General config index
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
/** @var \Illuminate\Pagination\LengthAwarePaginator $configList */
|
||||
$configList = GeneralConfig::query()->where('data', '!=', '[]')->paginate();
|
||||
return view('back::pages.general-configs.index', compact('configList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit general config
|
||||
*
|
||||
* @param \App\Models\Site\GeneralConfig $config
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factor
|
||||
*/
|
||||
public function edit(GeneralConfig $config)
|
||||
{
|
||||
return view('back::pages.general-configs.edit', ['config' => $config]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update General
|
||||
*
|
||||
* @param \App\Http\Requests\UpdateGeneralConfigRequest $request
|
||||
* @param \App\Models\Site\GeneralConfig $config
|
||||
* @return voi\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateGeneralConfigRequest $request, GeneralConfig $config)
|
||||
{
|
||||
$config->fill(array_replace_recursive(
|
||||
\json_decode(\json_encode($config->toArray()), true),
|
||||
$request->validated()
|
||||
));
|
||||
$config->saveOrFail();
|
||||
return redirect()->route('bo.general_configs.edit', $config)
|
||||
->with('bo.success', 'Enregistré !');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Magasin;
|
||||
use App\Models\CollecteException;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MagasinsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$magasins = Magasin::all();
|
||||
return view('bo.magasins.index', compact('magasins'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.magasins.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'address' => 'required|string|max:255',
|
||||
'postcode' => 'required',
|
||||
'city' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$shop = Magasin::create($request->except('_token'));
|
||||
return redirect()->route('bo.magasins.edit', $shop->id)->with('success', 'Nouveau Magasin enregistré !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$magasin = Magasin::findOrFail($id);
|
||||
$exceptionsCollecte = $magasin->collecteExceptions()->orderBy('date')->get();
|
||||
return view('bo.magasins.edit', compact('magasin', 'exceptionsCollecte'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'address' => 'required|string|max:255',
|
||||
'postcode' => 'required',
|
||||
'city' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$shop = Magasin::findOrFail($id);
|
||||
$shop->fill($request->except('_token'))->save();
|
||||
return redirect()->route('bo.magasins.edit', $shop->id)->with('success', 'Modifications enregistrés !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$shop = Magasin::findOrFail($id);
|
||||
|
||||
$count = Magasin::count();
|
||||
|
||||
if ($count === 1) {
|
||||
return redirect()->back()
|
||||
->withErrors("Suppression impossible : Vous devez conserver au moins 1 point de retrait.");
|
||||
}
|
||||
$shop->delete();
|
||||
return redirect()->route('bo.magasins.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* bo
|
||||
* ajx : affichage d'infos sur un magasin
|
||||
*
|
||||
* @param integer $id
|
||||
* @param string|null $mode
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getMagasinInfo(int $id, string $mode = null)
|
||||
{
|
||||
$magasin = Magasin::findOrFail($id);
|
||||
if (!is_null($mode)) {
|
||||
if ($mode == "tippy") {
|
||||
return view('bo.magasins.tippy-card', compact('magasin'));
|
||||
}
|
||||
if ($mode == "json") {
|
||||
return $magasin;
|
||||
}
|
||||
return view('bo.magasins.info-card', compact('magasin'));
|
||||
}
|
||||
return view('bo.magasins.info-popup', compact('magasin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save collect exceptions
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function saveExceptions(Request $request)
|
||||
{
|
||||
$collecteException = $request->collecte_exception;
|
||||
|
||||
$looplimit = count($collecteException);
|
||||
for ($i = 0; $i < $looplimit; $i++) {
|
||||
$collecteExceptionToInsert = !empty($collecteException[$i]["date"]);
|
||||
if (
|
||||
isset($collecteException[$i]["id"]) &&
|
||||
$collecteException[$i]["id"] !== null &&
|
||||
$collecteExceptionToInsert
|
||||
) {
|
||||
$ce = CollecteException::findOrFail($collecteException[$i]["id"]);
|
||||
$ce->date = $collecteException[$i]["date"];
|
||||
$ce->comment = $collecteException[$i]["comment"];
|
||||
$ce->magasin_id = $collecteException[$i]["magasin_id"];
|
||||
$ce->save();
|
||||
} else {
|
||||
if ($collecteExceptionToInsert) {
|
||||
$ce = CollecteException::updateOrCreate([
|
||||
'date' => $collecteException[$i]["date"],
|
||||
'comment' => $collecteException[$i]["comment"],
|
||||
'magasin_id' => $collecteException[$i]["magasin_id"]
|
||||
]);
|
||||
$collecteException[$i]["id"] = $ce->id;
|
||||
} else {
|
||||
unset($collecteException[$i]);
|
||||
$i--;
|
||||
}
|
||||
}
|
||||
}//end for
|
||||
|
||||
// Remet dans l'ordre avant de renvoyer.
|
||||
$this->arraySortByColumn($collecteException, "date");
|
||||
return $collecteException;
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $column
|
||||
* @param integer $direction
|
||||
* @return void
|
||||
*/
|
||||
public function arraySortByColumn(array &$array, string $column, int $direction = SORT_ASC)
|
||||
{
|
||||
$reference_array = array();
|
||||
|
||||
foreach ($array as $key => $row) {
|
||||
$reference_array[$key] = $row[$column];
|
||||
}
|
||||
|
||||
array_multisort($reference_array, $direction, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete collecte exception
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function destroyExceptions(Request $request)
|
||||
{
|
||||
$collecteException = CollecteException::findOrFail($request->id);
|
||||
$collecteException->delete();
|
||||
|
||||
return "Suppression terminée !";
|
||||
}
|
||||
}
|
||||
610
app/Http/Controllers/Bo/OrderController.php
Normal file
610
app/Http/Controllers/Bo/OrderController.php
Normal file
|
|
@ -0,0 +1,610 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\Order\DeliveryModeEnum;
|
||||
use App\Enums\Order\DeliveryStatus;
|
||||
use App\Enums\Order\PaymentModeEnum;
|
||||
use App\Enums\Order\TransactionStatus;
|
||||
use App\Enums\Order\TransactionType;
|
||||
use App\Enums\Order\ValidationStatus;
|
||||
use App\Events\OrderIsRefunded;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Orders\ChangeOrderDeliveryStatusRequest;
|
||||
use App\Http\Requests\Bo\Orders\ChangeOrderValidationStatusRequest;
|
||||
use App\Http\Requests\Bo\PrepareOrderRequest;
|
||||
use App\Http\Requests\Bo\ResolveOrderRequest;
|
||||
use App\Jobs\Order\RefundOrder;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Models\Payment\Transaction;
|
||||
use App\Models\Shop\Order;
|
||||
use Gloudemans\Shoppingcart\CartItem;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
/**
|
||||
* If true the index action will only display today orders
|
||||
* @var false
|
||||
*/
|
||||
private $indexModeTodayOnly = false;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $orders */
|
||||
$orders = Order::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$orders,
|
||||
$request->search,
|
||||
function (Builder $q) use ($request) {
|
||||
$q->orWhereHas('transactions', function (Builder $q) use ($request) {
|
||||
$foreignIds = \collect(PaymentModeEnum::toArray())
|
||||
->map(function (PaymentModeEnum $paymentMode) use ($request) {
|
||||
return Transaction::getPaymentForeignKeyName(
|
||||
$paymentMode,
|
||||
$request->search
|
||||
);
|
||||
});
|
||||
$q->whereIn('foreign_id', $foreignIds)
|
||||
->orWhereIn('foreign_refund_id', $foreignIds);
|
||||
});
|
||||
},
|
||||
'reference',
|
||||
'email',
|
||||
);
|
||||
}//end if
|
||||
|
||||
$this->sortQuery($orders);
|
||||
$searchFields = trans('Réference,Email,Pay.Ref');
|
||||
|
||||
if ($this->indexModeTodayOnly) {
|
||||
$orders->whereHas('timeslot', function (Builder $q) {
|
||||
$q->whereDate('slot', \now()->today());
|
||||
});
|
||||
}
|
||||
|
||||
$orders->orderBy('created_at', 'DESC');
|
||||
$orders->with(['deliveryMode', 'trashedTimeSlot.shop']);
|
||||
$orders = $orders->paginate(10);
|
||||
|
||||
return view('back::pages.orders.index', compact('orders', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function indexToday(Request $request): View
|
||||
{
|
||||
$this->indexModeTodayOnly = true;
|
||||
/** @var \Illuminate\View\View $response */
|
||||
$response = $this->callAction('index', ['request' => $request]);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function show(Order $order): View
|
||||
{
|
||||
$order->load('transactions');
|
||||
return view('back::pages.orders.show', compact('order'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre a jour le status de validation d'une commande
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Orders\ChangeOrderValidationStatusRequest $request
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function changeValidationStatus(ChangeOrderValidationStatusRequest $request, Order $order): RedirectResponse
|
||||
{
|
||||
$this->authorize('changeValidationStatus', $order);
|
||||
return DB::transaction(function () use ($request, $order) {
|
||||
$order->validation_status = $request->validation_status;
|
||||
switch ($request->validation_status) {
|
||||
case ValidationStatus::canceled()->value:
|
||||
$order->delivery_status = DeliveryStatus::canceled();
|
||||
\session()->flash('bo.warning', trans('La commande est marquée comme annulée'));
|
||||
// Fall through.
|
||||
case ValidationStatus::validated()->value:
|
||||
$order->saveOrFail();
|
||||
return \response()->redirectToRoute('bo.orders.show', $order)->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.orders'))]
|
||||
));
|
||||
case ValidationStatus::pending()->value:
|
||||
return \back()->with('bo.errors', \trans('Il faut choisir un statut pour cette commande.'));
|
||||
default:
|
||||
throw new \RuntimeException("Unhandled status `{$request->validation_status}`");
|
||||
}//end switch
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre a jour le status de livraison d'une commande
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Orders\ChangeOrderDeliveryStatusRequest $request
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function changeDeliveryStatus(ChangeOrderDeliveryStatusRequest $request, Order $order): RedirectResponse
|
||||
{
|
||||
$this->authorize('changeDeliveryStatus', $order);
|
||||
return DB::transaction(function () use ($request, $order) {
|
||||
$order->delivery_status = $request->delivery_status;
|
||||
switch (true) {
|
||||
// * La commande va être préparé ou est déja en cours de préparation
|
||||
case $order->delivery_status->equals(DeliveryStatus::preparation()) or
|
||||
$order->delivery_status->equals(DeliveryStatus::preparation()):
|
||||
$order->delivery_status = DeliveryStatus::preparation();
|
||||
$order->shipped_basket = '';
|
||||
$order->saveOrFail();
|
||||
return \redirect()->route('bo.orders.prepare', $order);
|
||||
// * La commande est récupérée.
|
||||
case $order->delivery_status->equals(DeliveryStatus::recovered()):
|
||||
// * Déclarer la commande comme réglée si récupération à la boutique.
|
||||
if ($order->deliveryMode->mode->equals(DeliveryModeEnum::inShop())) {
|
||||
// ! There should be one and only one inShop transaction !
|
||||
/** @var \App\Models\Payment\Transaction|null */
|
||||
$inShopTransaction = $order->transactions()
|
||||
->where('type', TransactionType::debit())
|
||||
->where('payment_mode', PaymentModeEnum::inShop())
|
||||
->latest()->first();
|
||||
$paidTransactions = $order->transactions()->where('type', TransactionType::debit())
|
||||
->where('status', TransactionStatus::validated())->count();
|
||||
// * Check if there are not paid transactions then
|
||||
// * we should have one pending inShop transaction.
|
||||
if (!$paidTransactions and !$inShopTransaction) {
|
||||
throw new \RuntimeException(
|
||||
"There should be one inshop transaction for order '{$order->id}'"
|
||||
);
|
||||
}
|
||||
if ($inShopTransaction) {
|
||||
$inShopTransaction->status = TransactionStatus::validated();
|
||||
$inShopTransaction->saveOrFail();
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException("Unhandled delivery mode other than in shop");
|
||||
} //end if
|
||||
// Fall through.
|
||||
// * La commande est prête.
|
||||
case $order->delivery_status->equals(DeliveryStatus::ready()):
|
||||
$order->saveOrFail();
|
||||
return \back()->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.orders'))]
|
||||
));
|
||||
default:
|
||||
throw new \RuntimeException("Unhandled status `{$request->delivery_status}`");
|
||||
}//end switch
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the order resolve form
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\View\View
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function resolve(Order $order): View
|
||||
{
|
||||
// phpcs:enable
|
||||
$this->authorize('resolve', $order);
|
||||
$transactionModel = $order->transactions()->where('needs_validation', true)->first();
|
||||
|
||||
// * Diff between Basket - (Delivered items - refunded transaction items)
|
||||
$remainingItems = $order->getRemainingUnrefundedItems();
|
||||
|
||||
return \view('back::pages.orders.resolve', \compact('order', 'transactionModel', 'remainingItems'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate order resolution
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\ResolveOrderRequest $request
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function resolveSubmit(ResolveOrderRequest $request, Order $order): RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $order) {
|
||||
/** @var \App\Models\Payment\Transaction */
|
||||
$transaction = $request->transaction;
|
||||
|
||||
/** @var \Illuminate\Support\Collection<object> */
|
||||
$orderedItems = \collect($order->basket);
|
||||
// * getRemainingUnrefundedItems Modifie les rowId originaux, il faut les restaurer pour la comparaison.
|
||||
/** @var \Illuminate\Support\Collection<string,string> */
|
||||
$refundedItems = $request->collect('items')->mapWithKeys(function (array $item) use ($orderedItems) {
|
||||
$item = (object)$item;
|
||||
$rowId = $orderedItems->where('id', '=', $item->index)->first()->rowId;
|
||||
return [$rowId => $item->quantity];
|
||||
});
|
||||
/** @var \Illuminate\Support\Collection<object> */
|
||||
$refundedTransactionsItems = $orderedItems->map(function (object $basketItem) use ($refundedItems) {
|
||||
if ($refundedItems->has($basketItem->rowId)) {
|
||||
$basketItem->qty = \intval($refundedItems->get($basketItem->rowId));
|
||||
return $basketItem;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
$refundedTransactionsItems = \collect(ToolboxHelper::updateBasketAmounts(
|
||||
$orderedItems,
|
||||
$refundedItems->all()
|
||||
));
|
||||
|
||||
// ? La transaction concerne des produits ?
|
||||
if ($refundedTransactionsItems->count()) {
|
||||
// * Estampiller les ligne avec la raison
|
||||
$refundedTransactionsItems->map(function (object $basketItem) use ($request) {
|
||||
$basketItem->name = "{$request->reason} - {$basketItem->name}";
|
||||
return $basketItem;
|
||||
});
|
||||
}
|
||||
|
||||
$montantRembourse = \intval($refundedTransactionsItems->sum('subtotal'));
|
||||
|
||||
// ? Le montant des produits remboursé est inférieur a celui de la transaction.
|
||||
if ($montantRembourse < \intval($transaction->amount->getAmount())) {
|
||||
// * Créer un dummy product pour représenter la transaction.
|
||||
$cartItemOptions = \array_merge(static::$cartItemOptionsSkel, [
|
||||
'virtual' => true,
|
||||
'price_ttc' => \intval($transaction->amount->getAmount()) - $montantRembourse,
|
||||
]);
|
||||
|
||||
$cartItem = CartItem::fromArray([
|
||||
'id' => \str_replace('.', '', \uniqid('', true)),
|
||||
'name' => $request->reason,
|
||||
'price' => \intval($transaction->amount->getAmount()) - $montantRembourse,
|
||||
'weight' => 0,
|
||||
'options' => $cartItemOptions
|
||||
]);
|
||||
$cartItem->setQuantity(1);
|
||||
|
||||
// * On envoie la ligne virtuelle en haut de la liste.
|
||||
$refundedTransactionsItems->put($cartItem->rowId, \json_decode($cartItem->toJson()));
|
||||
$refundedTransactionsItems = $refundedTransactionsItems->reverse();
|
||||
} //end if
|
||||
|
||||
$transaction->items = $refundedTransactionsItems->map(function (object $basketItem) {
|
||||
$basketItem->tax = $basketItem->tax * -1;
|
||||
$basketItem->price = $basketItem->price * -1;
|
||||
$basketItem->subtotal = $basketItem->subtotal * -1;
|
||||
$basketItem->options->price_ttc = $basketItem->options->price_ttc * -1;
|
||||
$basketItem->options->undiscounted_price_ttc =
|
||||
$basketItem->options->undiscounted_price_ttc * -1;
|
||||
return $basketItem;
|
||||
});
|
||||
$transaction->needs_validation = false;
|
||||
|
||||
// ? The resolution means a complete refund ?
|
||||
if ($order->isCompleteRefundWithTransaction($transaction)) {
|
||||
// * Calculate unrefunded tax
|
||||
$unRefundedTax = \abs(\intval(\collect($order->getRemainingUnrefundedItems())->sum(function (object $item) {
|
||||
return $item->tax * $item->qty;
|
||||
})));
|
||||
|
||||
// * Calculate justified items tax
|
||||
$justifiedItemTax = \abs(\intval(\collect($transaction->items)->sum(function (object $item) {
|
||||
return \optional($item->options)->virtual ? 0 : $item->tax * $item->qty;
|
||||
})));
|
||||
|
||||
// * Update remaining Tax to exclude justified.
|
||||
$remainingTax = ($unRefundedTax - $justifiedItemTax) * -1;
|
||||
|
||||
// * Set remaining tax to virtual
|
||||
$transaction->items = (object)\collect($transaction->items)
|
||||
->map(function (object $item) use ($remainingTax) {
|
||||
if (\optional($item->options)->virtual) {
|
||||
$item->tax = $remainingTax;
|
||||
}
|
||||
return $item;
|
||||
})->all();
|
||||
} //end if
|
||||
|
||||
$transaction->saveOrFail();
|
||||
|
||||
OrderIsRefunded::dispatch(
|
||||
$order,
|
||||
$transaction
|
||||
);
|
||||
|
||||
return \response()->redirectToRoute('bo.orders.show', $order)
|
||||
->with('success', \trans('La transaction est marquée comme résolue'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the order prepare form
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\View\View
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function prepare(Order $order): View
|
||||
{
|
||||
// phpcs:enable
|
||||
$this->authorize('prepare', $order);
|
||||
$remainingItems = $order->getRemainingUnrefundedItems();
|
||||
return \view('back::pages.orders.prepare', \compact('order', 'remainingItems'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate order preparation
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\PrepareOrderRequest $request
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function prepareSubmit(PrepareOrderRequest $request, Order $order): RedirectResponse
|
||||
{
|
||||
$this->authorize('prepare', $order);
|
||||
return DB::transaction(function () use ($request, $order) {
|
||||
|
||||
// * Les items qu'il reste sur la commande (non remboursés).
|
||||
$remainingItems = $order->getRemainingUnrefundedItems();
|
||||
|
||||
// * On met à jour cette liste avec les items effectivement préparés dans la commande.
|
||||
$shipped_basket = \collect(ToolboxHelper::updateBasketAmounts(
|
||||
$remainingItems,
|
||||
$request->items
|
||||
));
|
||||
|
||||
// * On met à jour la liste avec les items qui vont être remboursés.
|
||||
$itemsToRefund = $remainingItems->pluck('qty', 'id')
|
||||
->mapWithKeys(function ($qty, string $id) use ($request) {
|
||||
return [
|
||||
$id => \intval($qty) - \intval(\collect($request->items)->get($id, 0))
|
||||
];
|
||||
});
|
||||
$refundedTransactionsItems = \collect(ToolboxHelper::updateBasketAmounts(
|
||||
$remainingItems,
|
||||
$itemsToRefund->all()
|
||||
));
|
||||
|
||||
$order->shipped_basket = $shipped_basket;
|
||||
$order->delivery_status = DeliveryStatus::ready();
|
||||
// * Save Shipped basket
|
||||
$order->saveQuietly();
|
||||
|
||||
// ? Le montant va exceder ce que le client a payé ?
|
||||
if ($request->willExceedOrderAmount) {
|
||||
// * Annulation et remboursement du reste.
|
||||
// * Créer un dummy product pour représenter la transaction.
|
||||
$cartItemOptions = \array_merge(static::$cartItemOptionsSkel, [
|
||||
'virtual' => true,
|
||||
'price_ttc' => $order->total_ttc - $order->total_refund,
|
||||
]);
|
||||
|
||||
$cartItem = CartItem::fromArray([
|
||||
'id' => \str_replace('.', '', \uniqid('', true)),
|
||||
'name' => trans('Remboursement commande'),
|
||||
'price' => $order->total_ttc - $order->total_refund,
|
||||
'weight' => 0,
|
||||
'options' => $cartItemOptions
|
||||
]);
|
||||
$cartItem->setQuantity(1);
|
||||
|
||||
$this->refundTransaction(
|
||||
$order,
|
||||
$order->total_ttc - $order->total_refund,
|
||||
// * Negate all items prices (already refunded)
|
||||
\collect([
|
||||
$cartItem->rowId => \json_decode($cartItem->toJson())
|
||||
])->map(function (object $basketItem) {
|
||||
$basketItem->tax = $basketItem->tax * -1;
|
||||
$basketItem->price = $basketItem->price * -1;
|
||||
$basketItem->subtotal = $basketItem->subtotal * -1;
|
||||
$basketItem->options->price_ttc = $basketItem->options->price_ttc * -1;
|
||||
$basketItem->options->undiscounted_price_ttc =
|
||||
$basketItem->options->undiscounted_price_ttc * -1;
|
||||
return $basketItem;
|
||||
})
|
||||
);
|
||||
|
||||
// * Mettre a jour la commande.
|
||||
$order->saveOrFail();
|
||||
|
||||
// * Cancel Order completely.
|
||||
/** @var \Illuminate\Http\RedirectResponse */
|
||||
return $this->callAction('changeValidationStatus', [
|
||||
ChangeOrderValidationStatusRequest::create(
|
||||
\route('bo.orders.validation-status', $order),
|
||||
'POST',
|
||||
[
|
||||
'validation_status' => ValidationStatus::canceled()->value
|
||||
]
|
||||
),
|
||||
$order
|
||||
]);
|
||||
} //end if
|
||||
|
||||
// ? La commande va devoir être remboursé completement ?
|
||||
if ($request->willNeedCompleteRefund) {
|
||||
$this->refundTransaction(
|
||||
$order,
|
||||
$order->total_ttc - $order->total_refund,
|
||||
// * Negate all items prices (already refunded)
|
||||
$order->getRemainingUnrefundedItems()->map(function (object $basketItem) {
|
||||
$basketItem->tax = $basketItem->tax * -1;
|
||||
$basketItem->price = $basketItem->price * -1;
|
||||
$basketItem->subtotal = $basketItem->subtotal * -1;
|
||||
$basketItem->options->price_ttc = $basketItem->options->price_ttc * -1;
|
||||
$basketItem->options->undiscounted_price_ttc =
|
||||
$basketItem->options->undiscounted_price_ttc * -1;
|
||||
return $basketItem;
|
||||
})
|
||||
);
|
||||
|
||||
// * Mettre a jour la commande.
|
||||
$order->saveOrFail();
|
||||
|
||||
// * Cancel Order completely.
|
||||
/** @var \Illuminate\Http\RedirectResponse */
|
||||
return $this->callAction('changeValidationStatus', [
|
||||
ChangeOrderValidationStatusRequest::create(
|
||||
\route('bo.orders.validation-status', $order),
|
||||
'POST',
|
||||
[
|
||||
'validation_status' => ValidationStatus::canceled()->value
|
||||
]
|
||||
),
|
||||
$order
|
||||
]);
|
||||
} //end if
|
||||
|
||||
// ? Il faudra emettre un remboursement pour le reste ?
|
||||
if ($request->willNeedRefund and (bool)intval($refundedTransactionsItems->sum('subtotal'))) {
|
||||
$this->refundTransaction(
|
||||
$order,
|
||||
$refundedTransactionsItems->sum('subtotal'),
|
||||
// * Negate all items prices (already refunded)
|
||||
$refundedTransactionsItems->map(function (object $basketItem) {
|
||||
$basketItem->tax = $basketItem->tax * -1;
|
||||
$basketItem->price = $basketItem->price * -1;
|
||||
$basketItem->subtotal = $basketItem->subtotal * -1;
|
||||
$basketItem->options->price_ttc = $basketItem->options->price_ttc * -1;
|
||||
$basketItem->options->undiscounted_price_ttc =
|
||||
$basketItem->options->undiscounted_price_ttc * -1;
|
||||
return $basketItem;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// * Mettre a jour la commande.
|
||||
$order->saveOrFail();
|
||||
|
||||
return \redirect()->route('bo.orders.show', $order)->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.orders'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete order refund and cancel
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function cancelRefundSubmit(Order $order): RedirectResponse
|
||||
{
|
||||
$this->authorize('refund', $order);
|
||||
return DB::transaction(function () use ($order) {
|
||||
$this->callAction('refundSubmit', [$order]);
|
||||
// * Cancel Order completely.
|
||||
/** @var \Illuminate\Http\RedirectResponse */
|
||||
return $this->callAction('changeValidationStatus', [
|
||||
ChangeOrderValidationStatusRequest::create(
|
||||
\route('bo.orders.validation-status', $order),
|
||||
'POST',
|
||||
[
|
||||
'validation_status' => ValidationStatus::canceled()->value
|
||||
]
|
||||
),
|
||||
$order
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete order refund
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function refundSubmit(Order $order): RedirectResponse
|
||||
{
|
||||
$this->authorize('refund', $order);
|
||||
return DB::transaction(function () use ($order) {
|
||||
$this->refundTransaction(
|
||||
$order,
|
||||
$order->total_ttc - $order->total_refund,
|
||||
$order->getItemForOrderCancelling()
|
||||
);
|
||||
return \back()->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.orders'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund a transaction
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @param integer $amount
|
||||
* @param object $items
|
||||
* @return void
|
||||
* @throws \RuntimeException If the payment transaction cannot be fetched for the concerned order.
|
||||
*/
|
||||
private function refundTransaction(
|
||||
Order $order,
|
||||
int $amount,
|
||||
object $items
|
||||
): void {
|
||||
if (!($transaction = $order->getTransactionUsedForPayment())) {
|
||||
throw new \RuntimeException("Could not fetch paiment transaction for order {$order->id}");
|
||||
}
|
||||
|
||||
// ? Le paiment se fait en boutique ?
|
||||
if ($transaction->payment_mode->equals(PaymentModeEnum::inShop())) {
|
||||
// * Execute juste l'adaptateur.
|
||||
$newTransaction = $transaction->getAdapter()->doRefundCustomer(
|
||||
$transaction,
|
||||
$amount,
|
||||
$items
|
||||
);
|
||||
// ? On est sur la même transaction ?
|
||||
if ($newTransaction->exists and $newTransaction->id === $transaction->id) {
|
||||
// * Elle a été anullée.
|
||||
$previousMessage = session()->get('bo.warning', '');
|
||||
session()->flash('bo.warning', \trans(
|
||||
'La commande est annulée.'
|
||||
) . " {$previousMessage}");
|
||||
return;
|
||||
}
|
||||
// * Une nouvelle à été créé.
|
||||
$previousMessage = session()->get('bo.error', '');
|
||||
session()->flash(
|
||||
'bo.info',
|
||||
\trans(
|
||||
'Une nouvelle transaction est crée avec les produits effectivement préparés.'
|
||||
) . " {$previousMessage}"
|
||||
);
|
||||
return;
|
||||
} //end if
|
||||
RefundOrder::dispatchSync(
|
||||
$order,
|
||||
$transaction,
|
||||
$amount,
|
||||
$items
|
||||
);
|
||||
$previousMessage = session()->get('bo.info', '');
|
||||
session()->flash('bo.info', \trans(
|
||||
'Un remboursement va être émit au client'
|
||||
) . " \n{$previousMessage}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,610 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Order;
|
||||
use App\Models\OrderLine;
|
||||
use App\Models\OrdersProducts;
|
||||
use App\Models\Product;
|
||||
use App\Models\Timeslot;
|
||||
use App\Models\Magasin;
|
||||
use App\Http\Requests\SortOrders;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Mail\OrderStatusMail;
|
||||
use App\Mail\OrderConfirmMail;
|
||||
use App\Mail\OrderConfirmAdminMail;
|
||||
use App\Jobs\CsvOrderWrite;
|
||||
use App\Models\Customers;
|
||||
use App\Models\Setting;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterval;
|
||||
use Gloudemans\Shoppingcart\Facades\Cart;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
class OrdersController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Http\Requests\SortOrders $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(SortOrders $request)
|
||||
{
|
||||
$orders = $this->filterOrders($request);
|
||||
|
||||
$orders = $orders->paginate(10);
|
||||
|
||||
return view('bo.orders.index', compact('orders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* orders that ship today
|
||||
*
|
||||
* @param SortOrders $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function today(SortOrders $request)
|
||||
{
|
||||
$orders = $this->filterOrders($request);
|
||||
|
||||
// Filter today.
|
||||
$today = CarbonImmutable::now()->startOfDay();
|
||||
$orders = $orders->whereHas('timeslot', function ($q) use ($today) {
|
||||
$q->where('day', '=', $today->format('d/m/Y'));
|
||||
});
|
||||
|
||||
|
||||
$orders = $orders->get();
|
||||
return view('bo.orders.index', compact('orders', 'today'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter orders
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
protected function filterOrders(Request $request)
|
||||
{
|
||||
$orders = Order::query();
|
||||
|
||||
|
||||
if ($request->rst) {
|
||||
Session::remove('orders.sort_col');
|
||||
Session::remove('orders.sort_way');
|
||||
}
|
||||
if ($request->sort_col) {
|
||||
Session::put('orders.sort_col', $request->sort_col);
|
||||
Session::save();
|
||||
}
|
||||
if ($request->sort_way) {
|
||||
Session::put('orders.sort_way', $request->sort_way);
|
||||
Session::save();
|
||||
}
|
||||
|
||||
if (Session::has('orders.sort_col') and Session::has('orders.sort_way')) {
|
||||
switch (Session::get('orders.sort_col')) {
|
||||
case 'date':
|
||||
$orders = $orders->orderBy('date', Session::get('orders.sort_way'));
|
||||
break;
|
||||
case 'status_id':
|
||||
$orders = $orders->orderBy('status_id', Session::get('orders.sort_way'));
|
||||
break;
|
||||
case 'magasin_id':
|
||||
$orders = $orders->select('orders.*');
|
||||
$orders = $orders->leftJoin('timeslots', 'timeslots.order_id', '=', 'orders.id');
|
||||
$orders = $orders->leftJoin('magasins', 'timeslots.magasin_id', '=', 'magasins.id');
|
||||
$orders = $orders->orderBy('magasins.id', Session::get('orders.sort_way'));
|
||||
break;
|
||||
case 'date_retrait':
|
||||
$orders = $orders->select('orders.*');
|
||||
$orders = $orders->leftJoin('timeslots', 'timeslots.order_id', '=', 'orders.id');
|
||||
$orders = $orders->orderBy('timeslots.day', Session::get('orders.sort_way'));
|
||||
$orders = $orders->orderBy('timeslots.time', Session::get('orders.sort_way'));
|
||||
break;
|
||||
case 'customer_id':
|
||||
$orders = $orders->orderBy('customer_id', Session::get('orders.sort_way'));
|
||||
break;
|
||||
}//end switch
|
||||
}//end if
|
||||
|
||||
return $orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* action de changement de statut vers l'avant
|
||||
* envoi de mails transctionnels
|
||||
*
|
||||
* @param string $reference Reference de la commande.
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function changeStatus(string $reference)
|
||||
{
|
||||
$order = Order::where('reference', $reference)->first();
|
||||
$order->status_id = $order->status_id + 1;
|
||||
$order->save();
|
||||
|
||||
// Send confirm mail.
|
||||
Mail::to($order->customer->email)->send(new OrderStatusMail($order));
|
||||
|
||||
return back()->with('success', "Changement de status enregistré pour la commande " . $order->reference . ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* mise au statut annulé d'une commande
|
||||
*
|
||||
* @param string $reference
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function cancelOrder(string $reference)
|
||||
{
|
||||
$order = Order::where('reference', $reference)->first();
|
||||
$order->status_id = 7;
|
||||
$order->save();
|
||||
|
||||
return back()->with('success', "La commande " . $order->reference . " à été annulée.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Supprimer cette méthode qui repose sur un modèle de donnée osolète.
|
||||
* ajout de produits à la commande
|
||||
*
|
||||
* @param string $orderReference
|
||||
* @param integer $productId
|
||||
* @param integer $quantity
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function addProduct(string $orderReference, int $productId, int $quantity)
|
||||
{
|
||||
$product = Product::findOrFail($productId);
|
||||
$order = Order::where('reference', $orderReference)->first();
|
||||
|
||||
$order->total = $order->total + (($product->price - $product->price_buy) * $quantity);
|
||||
$orderProduct = new OrdersProducts();
|
||||
$orderProduct->product_id = $product->id;
|
||||
$orderProduct->order_id = $order->id;
|
||||
$orderProduct->quantity = $quantity;
|
||||
$orderProduct->save();
|
||||
|
||||
|
||||
return redirect()->route('bo.orders')->with('success', "Le produit à été ajouté.");
|
||||
}
|
||||
|
||||
/**
|
||||
* front
|
||||
* récap panier du tunnel de commande
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function recapOrder()
|
||||
{
|
||||
$activestep = 2;
|
||||
Cart::instance('panier');
|
||||
$cart = Cart::content();
|
||||
|
||||
$cartInfos = array(
|
||||
"totalTTC" => Cart::total(),
|
||||
// Total des taxes.
|
||||
'totalTVA' => Cart::tax(),
|
||||
// Total sans les taxes.
|
||||
'totalHT' => Cart::subtotal(),
|
||||
// Poids total des items.
|
||||
'totalweight' => Cart::weight(),
|
||||
// Total avant taxes et remises.
|
||||
'totalHTbefore' => Cart::priceTotal(),
|
||||
// Total des remises.
|
||||
'totaldiscount' => Cart::discount(),
|
||||
// Nb de produits dans le cart.
|
||||
'countItems' => Cart::count(),
|
||||
);
|
||||
|
||||
return view('sales.recap', compact('activestep', 'cart', 'cartInfos'));
|
||||
}
|
||||
|
||||
/**
|
||||
* front
|
||||
* Storing order from sales tunnel
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
// Save.
|
||||
Cart::instance('panier');
|
||||
$order = new Order();
|
||||
// Generate order ref.
|
||||
$order->reference = $this->generateOrderRef();
|
||||
$order->date = Carbon::now();
|
||||
$order->status_id = 1;
|
||||
$order->total = str_replace(',', '.', str_replace(' ', '', Cart::total()));
|
||||
$order->customer_id = Auth::user()->id;
|
||||
|
||||
$order->save();
|
||||
|
||||
// Order_id.
|
||||
Cart::instance('panier');
|
||||
$cart = Cart::content();
|
||||
foreach ($cart as $cartItem) {
|
||||
$order_line = new OrderLine();
|
||||
$order_line->order_id = $order->id;
|
||||
$order_line->product_id = $cartItem->model->id;
|
||||
$order_line->quantity = $cartItem->qty;
|
||||
// Gross unit price.
|
||||
$order_line->unit_price = $cartItem->model->priceHt;
|
||||
// Discount per unit.
|
||||
$order_line->unit_discount = $cartItem->model->discountAmount;
|
||||
// Tax rate for this line.
|
||||
$order_line->tax_rate = $cartItem->taxRate;
|
||||
// Tax amount par unit.
|
||||
$order_line->unit_tax = round(
|
||||
(($order_line->unit_price - $order_line->unit_discount) * ($order_line->tax_rate / 100)) * 100
|
||||
) / 100;
|
||||
// Discount amount for the line.
|
||||
$order_line->total_discount = $order_line->unit_discount * $order_line->quantity;
|
||||
// Gross amount for the line.
|
||||
$order_line->total_ht = ($order_line->unit_price - $order_line->unit_discount) * $order_line->quantity;
|
||||
// Tax amount for the line.
|
||||
$order_line->total_tax = $order_line->unit_tax * $order_line->quantity;
|
||||
// Total TTC avec remises de la ligne.
|
||||
$order_line->total_ttc = $order_line->total_ht + $order_line->total_tax;
|
||||
|
||||
$order_line->save();
|
||||
}//end foreach
|
||||
|
||||
// Empty cart.
|
||||
Cart::destroy();
|
||||
// Then redirect.
|
||||
return redirect()->route('sales.pick-slot', ['reference' => $order->reference]);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate order Reference
|
||||
* for a new order
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateOrderRef()
|
||||
{
|
||||
|
||||
// Format : YYYYMMDDHHMM000.
|
||||
$now = Carbon::now();
|
||||
// Count todays orders.
|
||||
$countorders = Order::whereDate('created_at', Carbon::today())->count();
|
||||
// Add one.
|
||||
$countorders++;
|
||||
$ref = $now->isoFormat('YYYYMMDDHHmm') . str_pad($countorders, 3, "0", STR_PAD_LEFT);
|
||||
return $ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* front tunnel de commande étape 3 : choix de créneau
|
||||
*
|
||||
* @param string $reference
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function timeSlotPick(string $reference)
|
||||
{
|
||||
$activestep = 3;
|
||||
if (config('theme.multi_relay')) {
|
||||
$magasin = Magasin::all();
|
||||
} else {
|
||||
$magasin = Magasin::first();
|
||||
}
|
||||
|
||||
$availCreneaux = array();
|
||||
$order = Order::where('reference', '=', $reference)->firstOrFail();
|
||||
|
||||
return view('sales.pick-slot', compact('activestep', 'availCreneaux', 'order', 'magasin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* add timeslot by interval between start and end hour
|
||||
*
|
||||
* @param array $plage
|
||||
* @param integer $weekDay
|
||||
* @param CarbonImmutable $current
|
||||
* @param Magasin $magasin
|
||||
* @param CarbonImmutable $now
|
||||
* @param CarbonImmutable $today
|
||||
* @param CarbonInterval $delaiPrepa
|
||||
* @param CarbonInterval $interval
|
||||
* @param Carbon $currentTime
|
||||
* @param Carbon $endTime
|
||||
* @return array
|
||||
*/
|
||||
private function addCreneaux(
|
||||
array $plage,
|
||||
int $weekDay,
|
||||
CarbonImmutable $current,
|
||||
Magasin $magasin,
|
||||
CarbonImmutable $now,
|
||||
CarbonImmutable $today,
|
||||
CarbonInterval $delaiPrepa,
|
||||
CarbonInterval $interval,
|
||||
Carbon $currentTime,
|
||||
Carbon $endTime
|
||||
) {
|
||||
$retArray = array();
|
||||
do {
|
||||
$creneau = $currentTime->format('H:i');
|
||||
$nbtakens = $magasin->timeslots()
|
||||
->where('day', $current->format('d/m/Y'))
|
||||
->where('time', $creneau)->count();
|
||||
|
||||
if ($nbtakens >= $plage[$weekDay]['max_orders_per_interval']) {
|
||||
$isDispo = false;
|
||||
} else {
|
||||
$isDispo = true;
|
||||
}
|
||||
|
||||
if (
|
||||
$current->addHours($currentTime->format('H'))->addMinutes($currentTime->format('i')) <
|
||||
$now->add($delaiPrepa)
|
||||
) {
|
||||
$isDispo = false;
|
||||
}
|
||||
// Attention si la date est passée (today mais avant maintenant) : pas de créneau.
|
||||
if ($current > $today || $currentTime >= $now) {
|
||||
$retArray[] = array($creneau, $isDispo);
|
||||
}
|
||||
$currentTime->add($interval);
|
||||
} while ($currentTime <= $endTime);
|
||||
return $retArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* give array of available crenaux
|
||||
*
|
||||
* @param integer $id
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailableCreneauxByShop(int $id)
|
||||
{
|
||||
// Setting à stocker et réutiliser.
|
||||
$plage_days = Setting::where('key', 'order_withdrawal_period')->firstOrFail()->value;
|
||||
|
||||
$magasin = Magasin::findOrFail($id);
|
||||
$timeslotSettings = $magasin->timeslotSettings;
|
||||
// $timeslotSettings = TimeslotSetting::all();
|
||||
// Fabriquons un tableau recap.
|
||||
$plage = array();
|
||||
foreach ($timeslotSettings as $day) {
|
||||
$plage[$day->day_index] = array(
|
||||
'morning_start' => $day->morning_start,
|
||||
'morning_end' => $day->morning_end,
|
||||
'afternoon_start' => $day->afternoon_start,
|
||||
'afternoon_end' => $day->afternoon_end,
|
||||
'interval' => $day->interval,
|
||||
'min_order_preparation' => $day->min_order_preparation,
|
||||
'max_orders_per_interval' => $day->max_orders_per_interval
|
||||
);
|
||||
}
|
||||
|
||||
// Génération des plages.
|
||||
// Start today.
|
||||
$today = CarbonImmutable::now()->startOfDay();
|
||||
$weekDay = $today->weekday();
|
||||
// Final boundary (permet de limiter la liste des jours d'exception).
|
||||
$finalday = $today->add($plage_days, 'day');
|
||||
$now = CarbonImmutable::now();
|
||||
// Jours exceptions.
|
||||
$noCollectDays = $magasin->collecteExceptions()
|
||||
->whereDate('date', '>', $now)
|
||||
->whereDate('date', '<=', $finalday)
|
||||
->orderBy('date')->get();
|
||||
|
||||
$delaiPrepa = CarbonInterval::createFromFormat('h:i', $plage[$weekDay]['min_order_preparation'] ?? '01:00');
|
||||
|
||||
$availCreneaux = array();
|
||||
|
||||
for ($i = 0; $i < $plage_days; $i++) {
|
||||
$current = $today->add($i, 'day');
|
||||
$weekDay = $current->weekday();
|
||||
$interval = CarbonInterval::createFromFormat('h:i', $plage[$weekDay]['interval'] ?? '00:15');
|
||||
|
||||
// Si c'est un jour exception skip.
|
||||
$skip = false;
|
||||
foreach ($noCollectDays as $not_today) {
|
||||
if ($current->isSameDay($not_today->date)) {
|
||||
$skip = true;
|
||||
}
|
||||
}
|
||||
if ($skip) {
|
||||
continue;
|
||||
}
|
||||
$availCreneaux[$current->format('d/m/Y')] = array();
|
||||
// Matinée.
|
||||
if (!empty($plage[$weekDay]['morning_start'])) {
|
||||
$currentTime = Carbon::createFromTimeString($plage[$weekDay]['morning_start']);
|
||||
$endTime = Carbon::createFromTimeString($plage[$weekDay]['morning_end']);
|
||||
|
||||
$morningCreneaux = $this->addCreneaux(
|
||||
$plage,
|
||||
$weekDay,
|
||||
$current,
|
||||
$magasin,
|
||||
$now,
|
||||
$today,
|
||||
$delaiPrepa,
|
||||
$interval,
|
||||
$currentTime,
|
||||
$endTime
|
||||
);
|
||||
|
||||
$availCreneaux[$current->format('d/m/Y')] = array_merge(
|
||||
$availCreneaux[$current->format('d/m/Y')],
|
||||
$morningCreneaux
|
||||
);
|
||||
} //end if
|
||||
// Aprem.
|
||||
if (!empty($plage[$weekDay]['afternoon_start'])) {
|
||||
$currentTime = Carbon::createFromTimeString($plage[$weekDay]['afternoon_start']);
|
||||
$endTime = Carbon::createFromTimeString($plage[$weekDay]['afternoon_end']);
|
||||
|
||||
$afternoonCreneaux = $this->addCreneaux(
|
||||
$plage,
|
||||
$weekDay,
|
||||
$current,
|
||||
$magasin,
|
||||
$now,
|
||||
$today,
|
||||
$delaiPrepa,
|
||||
$interval,
|
||||
$currentTime,
|
||||
$endTime
|
||||
);
|
||||
|
||||
$availCreneaux[$current->format('d/m/Y')] = array_merge(
|
||||
$availCreneaux[$current->format('d/m/Y')],
|
||||
$afternoonCreneaux
|
||||
);
|
||||
} //end if
|
||||
}//end for
|
||||
return $availCreneaux;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call ajax pour le composant vue de timeslots.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailableCreneaux(Request $request)
|
||||
{
|
||||
return $this->getAvailableCreneauxByShop($request->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* front
|
||||
* enregistrement du créneau de collect
|
||||
* et validation de la commande
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function setTimeSlot(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'selectedmagasin' => 'required',
|
||||
'selectedcreneau' => 'required',
|
||||
'ok_cgv' => 'accepted',
|
||||
]);
|
||||
|
||||
$time_slot = Carbon::createFromFormat('d/m/Y-H:i', $request->selectedcreneau);
|
||||
$tsday = explode('-', $request->selectedcreneau)[0];
|
||||
$tstime = explode('-', $request->selectedcreneau)[1];
|
||||
$magasin_id = $request->selectedmagasin;
|
||||
$reference = $request->order_ref;
|
||||
$order = Order::where('reference', '=', $reference)->firstOrFail();
|
||||
|
||||
if ($order->status_id == 1) {
|
||||
// On ne traite l'enregistrement que pour les commandes en attente venant de l'étape de récap.
|
||||
// Save timeslot.
|
||||
$timeslot = Timeslot::firstOrNew(['order_id' => $order->id]);
|
||||
$timeslot->order_id = $order->id;
|
||||
$timeslot->magasin_id = $magasin_id;
|
||||
$timeslot->day = $tsday;
|
||||
$timeslot->time = $tstime;
|
||||
$timeslot->save();
|
||||
|
||||
// Save order status.
|
||||
$order->status_id = 3;
|
||||
$order->save();
|
||||
|
||||
// Send confirm mail.
|
||||
Mail::to($order->customer->email)->queue(new OrderConfirmMail($order));
|
||||
|
||||
// Envoi du mail de confirmation aux admins site.
|
||||
$toMailSetting = Setting::where('key', 'send_order_confirm_mail_to')->first();
|
||||
if (empty($toMailSetting->value)) {
|
||||
$toMail = config('mail.from.address');
|
||||
} else {
|
||||
$toMail = $toMailSetting->value;
|
||||
}
|
||||
Mail::to($toMail)->queue(new OrderConfirmAdminMail($order));
|
||||
|
||||
// Export commande.
|
||||
if (config('bosettings.regate_orders')) {
|
||||
CsvOrderWrite::dispatch($order);
|
||||
}
|
||||
}//end if
|
||||
|
||||
// Redirect to final confirmation.
|
||||
return redirect()->route('sales.confirm', ['reference' => $order->reference]);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate Order
|
||||
* Test method
|
||||
*
|
||||
* @param string $reference
|
||||
* @return void
|
||||
*/
|
||||
public function generateOrder(string $reference)
|
||||
{
|
||||
$order = Order::where('reference', '=', $reference)->with('lines')->firstOrFail();
|
||||
$job = new CsvOrderWrite($order);
|
||||
$job->handle();
|
||||
dd('end');
|
||||
}
|
||||
|
||||
/**
|
||||
* front
|
||||
* page de confirmation de commande
|
||||
*
|
||||
* @param string $reference
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function confirmOrder(string $reference)
|
||||
{
|
||||
$activestep = 4;
|
||||
|
||||
$idcommande = Session::get('idcommande');
|
||||
$order = Order::where('reference', '=', $reference)->firstOrFail();
|
||||
|
||||
// 1 seul magasin en base pour le moment
|
||||
$magasin = Magasin::find($order->timeslot->magasin->id);
|
||||
|
||||
return view('sales.confirm', compact('activestep', 'order', 'magasin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* bo
|
||||
* ajx : affichage d'infos sur un client
|
||||
*
|
||||
* @param integer $id
|
||||
* @param string|null $mode
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getCustomerInfo(int $id, string $mode = null)
|
||||
{
|
||||
$cust = Customers::findOrFail($id);
|
||||
if (!is_null($mode)) {
|
||||
if ($mode == "tippy") {
|
||||
return view('bo.customer.tippy-card', compact('cust'));
|
||||
}
|
||||
if ($mode == "json") {
|
||||
return $cust->apiData;
|
||||
}
|
||||
return view('bo.customer.info-card', compact('cust'));
|
||||
}
|
||||
return view('bo.customer.info-popup', compact('cust'));
|
||||
}
|
||||
|
||||
/**
|
||||
* bo : page détail commande
|
||||
*
|
||||
* @param string $reference
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function orderDetail(string $reference)
|
||||
{
|
||||
$order = Order::where('reference', '=', $reference)->firstOrFail();
|
||||
return view('bo.orders.detail', compact('order'));
|
||||
}
|
||||
}
|
||||
62
app/Http/Controllers/Bo/PaymentModeController.php
Normal file
62
app/Http/Controllers/Bo/PaymentModeController.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\PaymentMode\UpdatePaymentModeRequest;
|
||||
use App\Models\Shop\PaymentMode;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class PaymentModeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$paymentModes = PaymentMode::paginate();
|
||||
|
||||
return view('back::pages.payment-modes.index', compact('paymentModes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Shop\PaymentMode $paymentMode
|
||||
* @return \Illuminate\Http\Response
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function edit(PaymentMode $paymentMode)
|
||||
{
|
||||
$this->authorize('update', PaymentMode::class);
|
||||
return view('back::pages.payment-modes.edit', compact(
|
||||
'paymentMode'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\UpdatePaymentModeRequest $request
|
||||
* @param \App\Models\Shop\PaymentMode $paymentMode
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdatePaymentModeRequest $request, PaymentMode $paymentMode)
|
||||
{
|
||||
$this->authorize('update', PaymentMode::class);
|
||||
$paymentMode->fill(array_replace_recursive(
|
||||
\json_decode(\json_encode($paymentMode->toArray()), true),
|
||||
$request->validated()
|
||||
));
|
||||
if ($paymentMode->saveOrFail()) {
|
||||
return redirect()->back()
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.payment_modes'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
}
|
||||
384
app/Http/Controllers/Bo/ProductController.php
Normal file
384
app/Http/Controllers/Bo/ProductController.php
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Products\CreateProductRequest;
|
||||
use App\Http\Requests\Bo\Products\StoreProductRequest;
|
||||
use App\Http\Requests\Bo\Products\UpdateProductRequest;
|
||||
use App\Models\Merchandise\Product;
|
||||
use App\Models\Merchandise\Range;
|
||||
use App\Models\Merchandise\Tag;
|
||||
use App\Models\XmlInco;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Kwaadpepper\ImageResizer\ImageResizer;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* If true the index action will only display starred products
|
||||
* @var false
|
||||
*/
|
||||
private $indexModeStarredOnly = false;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $products */
|
||||
$products = Product::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$products,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
'description',
|
||||
'reference'
|
||||
);
|
||||
} //end if
|
||||
|
||||
if ($request->range) {
|
||||
$products->whereHas('range', function (Builder $q) use ($request) {
|
||||
$q->where('id', $request->range);
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->type) {
|
||||
$products->where('type', $request->type);
|
||||
}
|
||||
|
||||
if ($indexModeStarredOnly = $this->indexModeStarredOnly ? true : false) {
|
||||
$products->where('star', true);
|
||||
}
|
||||
|
||||
if ($request->orderable) {
|
||||
$products->where('orderable', true);
|
||||
}
|
||||
if ($request->star) {
|
||||
$products->where('star', true);
|
||||
}
|
||||
|
||||
$this->sortQuery($products);
|
||||
$searchFields = trans('Nom, Description, Réf');
|
||||
|
||||
$products->orderBy('updated_at', 'DESC');
|
||||
$products->with(['range']);
|
||||
$products = $products->paginate();
|
||||
|
||||
$ranges = Range::all();
|
||||
|
||||
$productTypes = Product::fetchTypes();
|
||||
|
||||
return view('back::pages.products.index', compact(
|
||||
'indexModeStarredOnly',
|
||||
'products',
|
||||
'ranges',
|
||||
'searchFields',
|
||||
'productTypes'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* * Index des produits mis en avant
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function starred(Request $request)
|
||||
{
|
||||
$this->indexModeStarredOnly = true;
|
||||
return $this->callAction('index', [$request]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Products\CreateProductRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create(CreateProductRequest $request)
|
||||
{
|
||||
/** @var array product type Minicrud config */
|
||||
$minicrudData = Product::fetchTypesInputs()[$request->get('type')];
|
||||
|
||||
$ranges = Range::all();
|
||||
$tags = Tag::all();
|
||||
$existingProds = Product::all();
|
||||
|
||||
$productTypes = Product::fetchTypes();
|
||||
|
||||
return view('back::pages.products.create', \compact(
|
||||
'minicrudData',
|
||||
'productTypes',
|
||||
'existingProds',
|
||||
'ranges',
|
||||
'tags'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Products\StoreProductRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreProductRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$product = new Product();
|
||||
|
||||
// * Minicrud fill
|
||||
/** @var array product type Minicrud config */
|
||||
$minicrudData = Product::fetchTypesInputs()[$request->type];
|
||||
|
||||
$product->fill(array_replace_recursive(
|
||||
\json_decode(\json_encode((object)[
|
||||
'data' => $minicrudData
|
||||
]), true),
|
||||
$request->validated()
|
||||
));
|
||||
|
||||
if ($product->saveOrFail()) {
|
||||
$product->tags()->sync($request->tag_list);
|
||||
$product->associatedProducts()->sync($request->product_list);
|
||||
$product->saveOrFail();
|
||||
return redirect()
|
||||
->route('bo.products.edit', $product)
|
||||
->with('bo.success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Product $product)
|
||||
{
|
||||
$ranges = Range::all();
|
||||
$tags = Tag::all();
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<mixed,\App\Models\Merchandise\Product> */
|
||||
$selectedProds = $product->associatedProducts;
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<mixed,\App\Models\Merchandise\Product> */
|
||||
$existingProds = Product::query()->where('id', '!=', $product->id)->get();
|
||||
|
||||
$productTypes = Product::fetchTypes();
|
||||
|
||||
return view('back::pages.products.edit', [
|
||||
'productModel' => $product,
|
||||
'ranges' => $ranges,
|
||||
'tags' => $tags,
|
||||
'productTypes' => $productTypes,
|
||||
'existingProds' => $existingProds,
|
||||
'selectedProds' => $selectedProds
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Products\UpdateProductRequest $request
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateProductRequest $request, Product $product)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $product) {
|
||||
// * Minicrud fill
|
||||
$product->fill(array_replace_recursive(
|
||||
\json_decode(\json_encode($product->toArray()), true),
|
||||
$request->validated()
|
||||
));
|
||||
$product->makeStatusSense();
|
||||
$product->makeOrderableSense();
|
||||
|
||||
$product->tags()->sync($request->tag_list);
|
||||
$product->associatedProducts()->sync($request->product_list);
|
||||
|
||||
if ($product->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.products.edit', $product)
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
} //end if
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Product $product)
|
||||
{
|
||||
if ($product->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.products.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.products'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate XmlInco with product
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @param \App\Models\XmlInco $xml_inco
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function associateXmlInco(Product $product, XmlInco $xml_inco)
|
||||
{
|
||||
// * Allow if auth, request post and product type is inco
|
||||
Gate::allowIf(request()->isMethod('post'));
|
||||
$this->authorize('associateToInco', $product);
|
||||
|
||||
$product->makeStatusSense();
|
||||
$product->xmlInco()->associate($xml_inco);
|
||||
$product->saveOrFail();
|
||||
return redirect()->route('bo.products.edit', $product)
|
||||
->with('bo.success', trans(
|
||||
':model est associé avec fiche inco \':incoId\' \':descriptif\'',
|
||||
[
|
||||
'model' => Str::singular(trans('models.classes.slides')),
|
||||
'incoId' => $xml_inco->id,
|
||||
'descriptif' => Str::limit($xml_inco->descriptif)
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resize an inco picture and save to to the concerned product
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @param \App\Models\XmlInco $xml_inco
|
||||
* @param integer $picture_index
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \RuntimeException If anthing goes wrong managing disks files.
|
||||
* @throws \Kwaadpepper\ImageResizer\Exceptions\ImageResizerException If resizing the picture fails.
|
||||
* @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||
*/
|
||||
public function copyXmlIncoPicture(Product $product, XmlInco $xml_inco, int $picture_index): RedirectResponse
|
||||
{
|
||||
// * Check product is associated.
|
||||
if (!$product->xmlInco) {
|
||||
redirect()->route('bo.products.edit', $product)
|
||||
->withErrors(['xmlInco' => 'Vous devez d\'abord associer une fiche Inco']);
|
||||
}
|
||||
// * Check product inco is the same as requested.
|
||||
if ($product->xmlInco->id !== $xml_inco->id) {
|
||||
redirect()->route('bo.products.edit', $product)
|
||||
->withErrors(['xmlInco' => 'La fiche inco associé ne correspond pas à l\'image']);
|
||||
}
|
||||
|
||||
// * Allow if auth, request post and product type is inco and product has inco media on wanted index.
|
||||
Gate::allowIf(function ($user) use ($product, $xml_inco, $picture_index) {
|
||||
return $user and request()->isMethod('post') and
|
||||
$product->hasAndIsInco() and $xml_inco->mediaList->has($picture_index);
|
||||
});
|
||||
|
||||
/** @var array<string,string> Indexes are filename and imgdata */
|
||||
$picture = $xml_inco->mediaList->get($picture_index);
|
||||
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||
$storagePublicDisk = Storage::disk('public');
|
||||
$pictureBaseName = $picture['file_name'];
|
||||
$pictureExtension = \pathinfo($picture['file_name'], \PATHINFO_EXTENSION);
|
||||
|
||||
/**
|
||||
* We create one file in tmp to be resized
|
||||
* then use resize image to get cached file that we will copy.
|
||||
*/
|
||||
// * Make sys tmp file.
|
||||
if (!($file = tmpfile())) {
|
||||
throw new \RuntimeException('Failed to create tmp file handle');
|
||||
}
|
||||
|
||||
// * Wrap in try catch to always close tmp file
|
||||
try {
|
||||
// * Write picutre on tmp file.
|
||||
$path = stream_get_meta_data($file)['uri'];
|
||||
if (!File::put($path, $picture['imgdata'])) {
|
||||
throw new \RuntimeException('Failed to write content on tmp file');
|
||||
}
|
||||
|
||||
// * Assert theme config is present.
|
||||
if (
|
||||
!config()->has('theme.models.product.picture_maxheight') or
|
||||
!config()->has('theme.models.product.picture_maxwidth')
|
||||
) {
|
||||
throw new \RuntimeException('config theme.models.product needs picture_maxheight and picture_maxwidth');
|
||||
}
|
||||
|
||||
// * Dynamic push config.
|
||||
\config()->set('image-resizer.templates.incoPictureResizeForProduct', [
|
||||
'height' => config()->get('theme.models.product.picture_maxheight', 235),
|
||||
'width' => config()->get('theme.models.product.picture_maxwidth', 235),
|
||||
'format' => $pictureExtension,
|
||||
'inCanvas' => true,
|
||||
'resize' => true,
|
||||
'keepRatio' => true
|
||||
]);
|
||||
|
||||
// * Resize picture using kwaadpepper/image-resizer.
|
||||
$resizedPath = ImageResizer::resizeImageOrIgnore(
|
||||
$path,
|
||||
'incoPictureResizeForProduct'
|
||||
);
|
||||
if (!$storagePublicDisk->has($resizedPath)) {
|
||||
throw new \RuntimeException("Resized picture '$resizedPath' does not exists on 'public' disk");
|
||||
}
|
||||
|
||||
// * Append unique prefix to File original basename
|
||||
$pictureBaseNewName = Str::uuid() . '__' . $pictureBaseName;
|
||||
|
||||
// * Rename picture.
|
||||
$newPathName = \pathinfo($resizedPath, \PATHINFO_DIRNAME) . "/{$pictureBaseNewName}";
|
||||
if (!$storagePublicDisk->move($resizedPath, $newPathName)) {
|
||||
throw new \RuntimeException("Failed to rename '$resizedPath' into '$newPathName'");
|
||||
}
|
||||
|
||||
$product->picture = new \SplFileInfo($storagePublicDisk->path($newPathName));
|
||||
$product->saveOrFail();
|
||||
|
||||
// * remove tmp cached file.
|
||||
$storagePublicDisk->delete($newPathName);
|
||||
} finally {
|
||||
fclose($file);
|
||||
} //end try
|
||||
|
||||
return redirect()->route('bo.products.edit', $product);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,838 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ProductRequest;
|
||||
use App\Models\OldSlug;
|
||||
use App\Models\FoodProduct;
|
||||
use App\Models\ToolProduct;
|
||||
use App\Models\AnifoodProduct;
|
||||
use App\Models\GarmentProduct;
|
||||
use App\Models\Product;
|
||||
use App\Models\Range;
|
||||
use App\Models\Tag;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\XmlInco;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class ProductsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$ranges = Range::all();
|
||||
|
||||
$filter_range = $request->query('filter_range');
|
||||
$filter_name = $request->query('filter_name');
|
||||
|
||||
$products = new Product();
|
||||
|
||||
if (!empty($filter_name)) {
|
||||
$products = $products->where('name', 'like', '%' . $filter_name . '%');
|
||||
}
|
||||
if (!empty($filter_range)) {
|
||||
$products = $products->where('range_id', $filter_range);
|
||||
}
|
||||
$products = $products->paginate(10);
|
||||
|
||||
// Ici récupération des infos additionnelles pour affichage dans la liste.
|
||||
foreach ($products as &$product) {
|
||||
if (!empty($product->product_type)) {
|
||||
$product->additionnalProductInfo = $product->additionnalProductInfo($product->product_type);
|
||||
if ($product->additionnalProductInfo === null) {
|
||||
// N'existe pas on renseigne un vide.
|
||||
$product_type = $product->product_type;
|
||||
$modelClass = 'App\Models\\' . ucfirst($product_type);
|
||||
$product->$product_type = new $modelClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($product);
|
||||
return view('bo.products.index', compact('products', 'ranges', 'filter_name', 'filter_range'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @param string $product_type
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create(string $product_type = null)
|
||||
{
|
||||
if (!empty($product_type) && !array_key_exists($product_type, config('theme.enum_product_types'))) {
|
||||
abort(404, "Cette page n'existe pas.");
|
||||
}
|
||||
$modelClass = 'App\Models\\' . ucfirst($product_type);
|
||||
$product = new Product();
|
||||
if (!empty($product_type)) {
|
||||
$product->$product_type = new $modelClass();
|
||||
}
|
||||
$ranges = Range::all();
|
||||
$taxes = TaxRate::all();
|
||||
return view('bo.products.create', compact('product_type', 'product', 'ranges', 'taxes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* store a new product
|
||||
*
|
||||
* @param ProductRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(ProductRequest $request)
|
||||
{
|
||||
// Products fields.
|
||||
$name = $request->name;
|
||||
$description = $request->description;
|
||||
$picture = $request->picture;
|
||||
$picture_large = $request->picture_large;
|
||||
$price = $request->price;
|
||||
$invoicing_unit = $request->invoicing_unit;
|
||||
$priceBuy = $request->price_buy;
|
||||
$order_unit = $request->order_unit;
|
||||
$stock = $request->stock;
|
||||
$reference = $request->reference;
|
||||
$sell_unit = $request->sell_unit;
|
||||
$weight = $request->weight;
|
||||
$weight_unit = $request->weight_unit;
|
||||
$status = $request->status === null ? 0 : 1;
|
||||
$orderable_start = $request->orderable_start_date === null ? null
|
||||
: $request->orderable_start_date . " " . $request->orderable_start_time;
|
||||
$orderable_end = $request->orderable_end_date === null ? null
|
||||
: $request->orderable_end_date . " " . $request->orderable_end_time;
|
||||
$star = $request->star === null ? 0 : 1;
|
||||
$slug = Str::slug($name);
|
||||
$rangeId = $request->range_id;
|
||||
$taxRateId = $request->tax_rate_id;
|
||||
|
||||
|
||||
// Check si le slug existe déjà dans cette gamme de produits.
|
||||
$slugExist = Product::where([
|
||||
['range_id', $rangeId],
|
||||
['slug', $slug]
|
||||
])->first();
|
||||
|
||||
if ($slugExist) {
|
||||
return redirect()->back()
|
||||
->withInput($request->input())
|
||||
->withErrors("Erreur : un produit avec le slug d'accès \"" . $slug .
|
||||
"\" éxiste déjà. Veuillez changer le nom du produit.");
|
||||
}
|
||||
|
||||
$product = new Product();
|
||||
$product->name = $name;
|
||||
$product->description = $description;
|
||||
$product->price = $price;
|
||||
$product->invoicing_unit = $invoicing_unit;
|
||||
$product->price_buy = $priceBuy;
|
||||
$product->order_unit = $order_unit;
|
||||
$product->stock = $stock;
|
||||
$product->reference = $reference;
|
||||
$product->sell_unit = $sell_unit;
|
||||
$product->weight = $weight;
|
||||
$product->weight_unit = $weight_unit;
|
||||
$product->slug = $slug;
|
||||
$product->status = $status;
|
||||
$product->orderable_start = $orderable_start;
|
||||
$product->orderable_end = $orderable_end;
|
||||
$product->star = $star;
|
||||
$product->range_id = $rangeId;
|
||||
$product->tax_rate_id = $taxRateId;
|
||||
$product->save();
|
||||
|
||||
// Check si le slug existe dans la table old_slugs, auquel cas il est attribué a ce nouveau produit.
|
||||
$oldSlug = OldSlug::where('slug', $slug)->first();
|
||||
if ($oldSlug && $oldSlug->product_id !== $product->id) {
|
||||
$oldSlug->product_id = $product->id;
|
||||
$oldSlug->save();
|
||||
}
|
||||
|
||||
$str_random = Str::random(5);
|
||||
|
||||
if ($picture !== null) {
|
||||
$imageName = $product->id . '_' . $str_random . '.' . $picture->extension();
|
||||
$picture->move(public_path('images/produits'), $imageName);
|
||||
$product->picture = $imageName;
|
||||
$product->save();
|
||||
}
|
||||
|
||||
if ($picture_large !== null) {
|
||||
$imageName = $product->id . '_' . $str_random . '_large.' . $picture_large->extension();
|
||||
$picture_large->move(public_path('images/produits'), $imageName);
|
||||
$product->picture_large = $imageName;
|
||||
$product->save();
|
||||
}
|
||||
|
||||
// Ajout des infos additionnelles.
|
||||
$product_type = $request->product_type;
|
||||
|
||||
if ($product_type !== null) {
|
||||
$product->product_type = $product_type;
|
||||
$product->save();
|
||||
$methodName = "save" . ucfirst($product_type);
|
||||
$this->$methodName($request, $product->id);
|
||||
}
|
||||
|
||||
|
||||
// Additionnal product info (foodProduct).
|
||||
return redirect()->route('bo.products.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$product = Product::findOrFail($id);
|
||||
if (!empty($product->product_type)) {
|
||||
$product->additionnalProductInfo = $product->additionnalProductInfo($product->product_type);
|
||||
/**
|
||||
* Above lines equivalent to
|
||||
* $product = Product::with('additionnalProductInfo')->findOrFail($id);
|
||||
*/
|
||||
if ($product->additionnalProductInfo === null) {
|
||||
// N'existe pas on renseigne un vide.
|
||||
$product_type = $product->product_type;
|
||||
$modelClass = 'App\Models\\' . ucfirst($product_type);
|
||||
$product->$product_type = new $modelClass();
|
||||
}
|
||||
}
|
||||
|
||||
$ranges = Range::all();
|
||||
$taxes = TaxRate::all();
|
||||
$existingTags = Tag::all();
|
||||
$selectedtags = $product->tags;
|
||||
|
||||
$existingProds = Product::all();
|
||||
$selectedProds = $product->products;
|
||||
$existingProds = $existingProds->diff($selectedProds);
|
||||
|
||||
return view('bo.products.edit', compact(
|
||||
'product',
|
||||
'ranges',
|
||||
'taxes',
|
||||
'existingTags',
|
||||
'selectedtags',
|
||||
'existingProds',
|
||||
'selectedProds'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource.
|
||||
*
|
||||
* @param \App\Models\Product $product
|
||||
* @param ProductRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Product $product, ProductRequest $request)
|
||||
{
|
||||
$orderable_end_time = $request->orderable_end_time === null ? "23:59" : $request->orderable_end_time;
|
||||
|
||||
$name = $request->name;
|
||||
$description = $request->description;
|
||||
$price = $request->price;
|
||||
$invoicing_unit = $request->invoicing_unit;
|
||||
$priceBuy = $request->price_buy;
|
||||
$order_unit = $request->order_unit;
|
||||
$stock = $request->stock;
|
||||
$reference = $request->reference;
|
||||
$sell_unit = $request->sell_unit;
|
||||
$weight = $request->weight;
|
||||
$weight_unit = $request->weight_unit;
|
||||
$status = $request->status === null ? 0 : 1;
|
||||
$orderable_start = $request->orderable_start_date === null ? null
|
||||
: $request->orderable_start_date . " " . $request->orderable_start_time;
|
||||
$orderable_end = $request->orderable_end_date === null ? null
|
||||
: $request->orderable_end_date . " " . $orderable_end_time;
|
||||
$star = $request->star === null ? 0 : 1;
|
||||
$slug = Str::slug($name);
|
||||
$rangeId = $request->range_id;
|
||||
$taxRateId = $request->tax_rate_id;
|
||||
|
||||
$this->checkSlugExistsWithinRange($request, $rangeId, $slug, $product->id);
|
||||
|
||||
$this->manageProductImages($request->picture, $product, $request->picture_large);
|
||||
|
||||
$product->name = $name;
|
||||
|
||||
$this->saveNewSlugForProduct($product, $slug);
|
||||
|
||||
$product->description = $description;
|
||||
$product->price = $price;
|
||||
$product->invoicing_unit = $invoicing_unit;
|
||||
$product->price_buy = $priceBuy;
|
||||
$product->order_unit = $order_unit;
|
||||
$product->stock = $stock;
|
||||
$product->reference = $reference;
|
||||
$product->sell_unit = $sell_unit;
|
||||
$product->weight = $weight;
|
||||
$product->weight_unit = $weight_unit;
|
||||
$product->slug = $slug;
|
||||
$product->status = $status;
|
||||
$product->orderable_start = $orderable_start;
|
||||
$product->orderable_end = $orderable_end;
|
||||
$product->star = $star;
|
||||
$product->range_id = $rangeId;
|
||||
$product->tax_rate_id = $taxRateId;
|
||||
$product->save();
|
||||
|
||||
// Check si le slug existe dans la table old_slug, auquel cas il est attribué a ce nouveau produit.
|
||||
$this->cleanOldSlug($slug);
|
||||
|
||||
// Ajout des infos additionnelles.
|
||||
$product_type = $request->product_type;
|
||||
|
||||
// Save additionnal.
|
||||
if ($product_type !== null) {
|
||||
$methodName = "save" . ucfirst($product_type);
|
||||
$this->$methodName($request, $product->id);
|
||||
}
|
||||
|
||||
// Tags associés.
|
||||
$this->syncTags($request->tags, $product);
|
||||
|
||||
// Produits associés.
|
||||
$this->syncProduitsAssocies($request->prods, $product);
|
||||
|
||||
return redirect()->route('bo.products.edit', $product->id)->with('success', 'Modifications enregistrés !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if slug already exists, if so redirect
|
||||
*
|
||||
* @param Request $request
|
||||
* @param integer $rangeId
|
||||
* @param string $slug
|
||||
* @param integer|null $productId
|
||||
* @return \Illuminate\Http\RedirectResponse|void
|
||||
*/
|
||||
private function checkSlugExistsWithinRange(Request $request, int $rangeId, string $slug, int $productId = null)
|
||||
{
|
||||
// Check si le slug existe déjà dans cette gamme de produits.
|
||||
$slugExist = Product::where([
|
||||
['range_id', $rangeId],
|
||||
['slug', $slug],
|
||||
['id', '<>', $productId]
|
||||
])->first();
|
||||
|
||||
if ($slugExist) {
|
||||
return redirect()->back()
|
||||
->withInput($request->input())
|
||||
->withErrors("Erreur : un produit avec le slug d'accès \"" . $slug .
|
||||
"\" éxiste déjà. Veuillez changer le nom du produit.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If new slug for product then save oldslug
|
||||
*
|
||||
* @param Product $product
|
||||
* @param string $slug
|
||||
* @return void
|
||||
*/
|
||||
private function saveNewSlugForProduct(Product $product, string $slug)
|
||||
{
|
||||
if ($product->slug != $slug) {
|
||||
$exist = OldSlug::where('slug', $product->slug)->first();
|
||||
if ($exist === null) {
|
||||
$oldSlug = new OldSlug();
|
||||
$oldSlug->product_id = $product->id;
|
||||
$oldSlug->slug = $product->slug;
|
||||
$oldSlug->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clean oldslug if exists
|
||||
*
|
||||
* @param string $slug
|
||||
* @return void
|
||||
*/
|
||||
private function cleanOldSlug(string $slug)
|
||||
{
|
||||
// Check si le slug existe dans la table old_slug, auquel cas il est attribué a ce nouveau produit.
|
||||
$oldSlug = OldSlug::where('slug', $slug)->first();
|
||||
if ($oldSlug) {
|
||||
$oldSlug->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store and update saved images on product
|
||||
*
|
||||
* @param UploadedFile|null $picture
|
||||
* @param Product $product
|
||||
* @param UploadedFile|null $picture_large
|
||||
* @return void
|
||||
*/
|
||||
private function manageProductImages($picture, Product &$product, $picture_large)
|
||||
{
|
||||
|
||||
$str_random = Str::random(5);
|
||||
|
||||
if ($picture !== null) {
|
||||
if (
|
||||
$product->picture !== null &&
|
||||
file_exists(public_path('images/produits/') . $product->picture)
|
||||
) {
|
||||
unlink(public_path('images/produits/') . $product->picture);
|
||||
}
|
||||
$imageName = $product->id . '_' . $str_random . '.' . $picture->extension();
|
||||
$picture->move(public_path('images/produits'), $imageName);
|
||||
$product->picture = $imageName;
|
||||
}
|
||||
|
||||
if ($picture_large !== null) {
|
||||
if (
|
||||
$product->picture_large !== null &&
|
||||
file_exists(public_path('images/produits/') . $product->picture_large)
|
||||
) {
|
||||
unlink(public_path('images/produits/') . $product->picture_large);
|
||||
}
|
||||
$imageName = $product->id . '_' . $str_random . '_large.' . $picture_large->extension();
|
||||
$picture_large->move(public_path('images/produits'), $imageName);
|
||||
$product->picture_large = $imageName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sync tags to product
|
||||
*
|
||||
* @param array|null $tags
|
||||
* @param Product $product
|
||||
* @return void
|
||||
*/
|
||||
private function syncTags(array $tags = null, Product &$product)
|
||||
{
|
||||
if (!empty($tags)) {
|
||||
$arTagIds = array();
|
||||
foreach ($tags as $tag) {
|
||||
$oTag = json_decode($tag);
|
||||
if (empty($oTag->id)) {
|
||||
// We need a new tag.
|
||||
$arTagIds[] = $this->storeTag($oTag);
|
||||
} else {
|
||||
$arTagIds[] = $oTag->id;
|
||||
}
|
||||
}
|
||||
// Prise en charge de la liaison avec les produits.
|
||||
$product->tags()->sync($arTagIds);
|
||||
} else {
|
||||
$product->tags()->sync(array());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sync associated products to product
|
||||
*
|
||||
* @param string|null $prods
|
||||
* @param Product $product
|
||||
* @return void
|
||||
*/
|
||||
private function syncProduitsAssocies(string $prods = null, Product $product)
|
||||
{
|
||||
if (!empty($prods)) {
|
||||
$productIds = explode(",", $prods);
|
||||
// Prise en charge de la liaison avec les produits.
|
||||
$product->products()->sync($productIds);
|
||||
} else {
|
||||
$product->products()->sync(array());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to store a new tag if necessary
|
||||
* Otherwise retreive an existing tag to associate its id
|
||||
*
|
||||
* @param \App\Models\Tag $oTag
|
||||
* @return integer
|
||||
*/
|
||||
public function storeTag(Tag $oTag)
|
||||
{
|
||||
$slug = Str::slug($oTag->label);
|
||||
$tag = Tag::where('slug', $slug)->first();
|
||||
if ($tag === null) {
|
||||
// Si on pas encore ce tag on le crée.
|
||||
$tag = new Tag();
|
||||
$tag->label = $oTag->label;
|
||||
$tag->slug = Str::slug($oTag->label);
|
||||
// A new tag is published by default.
|
||||
$tag->status = 1;
|
||||
$tag->order = TagsController::getLastOrder();
|
||||
$tag->save();
|
||||
}
|
||||
return $tag->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy a product (soft delete)
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$product = Product::findOrFail($id);
|
||||
|
||||
if ($product->picture !== null && file_exists(public_path('images/produits/') . $product->picture)) {
|
||||
unlink(public_path('images/produits/') . $product->picture);
|
||||
}
|
||||
if (
|
||||
$product->picture_large !== null &&
|
||||
file_exists(public_path('images/produits/') . $product->picture_large)
|
||||
) {
|
||||
unlink(public_path('images/produits/') . $product->picture_large);
|
||||
}
|
||||
|
||||
OldSlug::where('product_id', $product->id)->delete();
|
||||
|
||||
$product->delete();
|
||||
return redirect()->route('bo.products.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* check if inco data exists
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function checkIncoData(Request $request)
|
||||
{
|
||||
$id = $request->id;
|
||||
$xmlInco = XmlInco::find($id);
|
||||
|
||||
if (!empty($xmlInco)) {
|
||||
// We have data.
|
||||
$hasInco = __("Des données Inco sont disponibles, souhaitez vous les associer à ce produit ?");
|
||||
$preparedImages = $this->prepareIncoImages($xmlInco->picture);
|
||||
return view('bo.products.load-inco', compact('hasInco', 'xmlInco', 'preparedImages'));
|
||||
} else {
|
||||
return array("data" => array());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show prepared images
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getPrepareIncoImages(Request $request)
|
||||
{
|
||||
$picture = $request->picture;
|
||||
$preparedImages = $this->prepareIncoImages($picture);
|
||||
return view('bo.products.inco-images', compact('preparedImages'));
|
||||
}
|
||||
|
||||
/**
|
||||
* prepared images
|
||||
*
|
||||
* @param array $picture
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function prepareIncoImages(array $picture)
|
||||
{
|
||||
$preparedImages = array();
|
||||
|
||||
foreach ($picture as $incoImage) {
|
||||
// Charge.
|
||||
if (File::exists(storage_path($incoImage))) {
|
||||
$imagePath = storage_path($incoImage);
|
||||
// Redimensionne.
|
||||
// Create mask.
|
||||
// Resize original image into mask.
|
||||
$this->resizeImg(
|
||||
$imagePath,
|
||||
config('theme.product_image_large_maxwidth'),
|
||||
config('theme.product_image_large_maxheight'),
|
||||
File::name($incoImage) . "_large.png"
|
||||
);
|
||||
|
||||
$this->resizeImg(
|
||||
$imagePath,
|
||||
config('theme.product_image_maxwidth'),
|
||||
config('theme.product_image_maxheight'),
|
||||
File::name($incoImage) . "_small.png"
|
||||
);
|
||||
|
||||
|
||||
$preparedImages[] = "inco/images/" . File::name($incoImage) . "_large.png";
|
||||
}//end if
|
||||
}//end foreach
|
||||
return $preparedImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* redimensionne une image dans un masque
|
||||
*/
|
||||
/**
|
||||
* redimensionne une image dans un masque
|
||||
*
|
||||
* @param string $imagePath
|
||||
* @param integer $maskWidth
|
||||
* @param integer $maskHeight
|
||||
* @param string $resizedName
|
||||
* @return boolean|void
|
||||
*/
|
||||
private function resizeImg(string $imagePath, int $maskWidth, int $maskHeight, string $resizedName)
|
||||
{
|
||||
// ---- création du masque
|
||||
$mask = imagecreatetruecolor($maskWidth, $maskHeight);
|
||||
imagesavealpha($mask, true);
|
||||
$color = imagecolorallocatealpha($mask, 0, 0, 0, 127);
|
||||
imagefill($mask, 0, 0, $color);
|
||||
|
||||
// ---- Récupère le mime type de l'image
|
||||
$info = getimagesize($imagePath);
|
||||
$mime = $info['mime'];
|
||||
|
||||
// ---- Défini les fonctions à appeler selon le type de fichier
|
||||
switch ($mime) {
|
||||
case 'image/jpeg':
|
||||
$image_create_func = 'imagecreatefromjpeg';
|
||||
break;
|
||||
|
||||
case 'image/png':
|
||||
$image_create_func = 'imagecreatefrompng';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---- Chargement de l'image source
|
||||
$img = $image_create_func($imagePath);
|
||||
list($imgWidth, $imgHeight) = getimagesize($imagePath);
|
||||
|
||||
// ---- Calcul les nouvelles dimensions de l'image
|
||||
if ($imgWidth > $imgHeight) {
|
||||
$finalWidth = $maskWidth;
|
||||
$finalHeight = ($finalWidth * $imgHeight) / $imgWidth;
|
||||
} else {
|
||||
$finalHeight = $maskHeight;
|
||||
$finalWidth = ($finalHeight * $imgWidth) / $imgHeight;
|
||||
}
|
||||
|
||||
// ---- Redimensionne l'image source
|
||||
$resizeImg = imagecreatetruecolor($finalWidth, $finalHeight);
|
||||
imagealphablending($resizeImg, false);
|
||||
imagesavealpha($resizeImg, true);
|
||||
imagecopyresampled($resizeImg, $img, 0, 0, 0, 0, $finalWidth, $finalHeight, $imgWidth, $imgHeight);
|
||||
|
||||
// Copie l'image redimensionnée dans le mask.
|
||||
imagecopy(
|
||||
$mask,
|
||||
$resizeImg,
|
||||
($maskWidth - $finalWidth) / 2,
|
||||
($maskHeight - $finalHeight) / 2,
|
||||
0,
|
||||
0,
|
||||
imagesx($resizeImg),
|
||||
imagesy($resizeImg)
|
||||
);
|
||||
imagealphablending($mask, false);
|
||||
imagesavealpha($mask, true);
|
||||
|
||||
// Ecrit dans storage/app/public.
|
||||
// Créer le fichier final.
|
||||
imagepng($mask, storage_path('app/public/inco/images/' . $resizedName), 5);
|
||||
|
||||
// Libère la mémoire associée aux images manipulées.
|
||||
imagedestroy($img);
|
||||
imagedestroy($resizeImg);
|
||||
imagedestroy($mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* set une image préparée comme image du produit
|
||||
*/
|
||||
/**
|
||||
* set une image préparée comme image du produit
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \App\Models\Product
|
||||
*/
|
||||
public function setIncoImage(Request $request)
|
||||
{
|
||||
$imagePath = $request->picture;
|
||||
|
||||
$imagePath = storage_path("app/public/" . $imagePath);
|
||||
|
||||
$product_id = $request->product;
|
||||
$product = Product::findOrFail($product_id);
|
||||
|
||||
$str_random = Str::random(5);
|
||||
// Default is large image.
|
||||
$finalImageName = $product->id . '_' . $str_random . '_large.' . File::extension($imagePath);
|
||||
|
||||
$productimagespath = public_path('images/produits');
|
||||
|
||||
if (!File::isDirectory($productimagespath)) {
|
||||
File::makeDirectory($productimagespath, 0644, true);
|
||||
}
|
||||
|
||||
File::copy($imagePath, $productimagespath . "/" . $finalImageName);
|
||||
|
||||
// Suppression de l'ancien fichier.
|
||||
if (
|
||||
$product->picture_large !== null &&
|
||||
file_exists(public_path('images/produits/') . $product->picture_large)
|
||||
) {
|
||||
unlink(public_path('images/produits/') . $product->picture_large);
|
||||
}
|
||||
|
||||
$product->picture_large = $finalImageName;
|
||||
|
||||
|
||||
// Now set small image.
|
||||
$imagePath = str_replace("_large", "_small", $imagePath);
|
||||
$finalImageName = $product->id . '_' . $str_random . '.' . File::extension($imagePath);
|
||||
File::copy($imagePath, $productimagespath . "/" . $finalImageName);
|
||||
|
||||
// Suppression de l'ancien fichier.
|
||||
if ($product->picture !== null && file_exists(public_path('images/produits/') . $product->picture)) {
|
||||
unlink(public_path('images/produits/') . $product->picture);
|
||||
}
|
||||
|
||||
$product->picture = $finalImageName;
|
||||
|
||||
$product->save();
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* helper method to update additionnal product info
|
||||
*
|
||||
* @param Request $request
|
||||
* @param integer $product_id
|
||||
* @return void
|
||||
*/
|
||||
public function saveFoodProduct(Request $request, int $product_id)
|
||||
{
|
||||
$foodProduct = FoodProduct::firstOrNew([
|
||||
'product_id' => $product_id,
|
||||
]);
|
||||
|
||||
if (!empty($request->no_art)) {
|
||||
$foodProduct->no_art = $request->no_art;
|
||||
}
|
||||
$foodProduct->ingredients = $request->ingredients;
|
||||
$foodProduct->preparation = $request->preparation;
|
||||
$foodProduct->servings = $request->servings;
|
||||
$foodProduct->allergens = $request->allergens;
|
||||
$foodProduct->selling_argument = $request->selling_argument;
|
||||
$foodProduct->nv_ref_weight_g = $request->nv_ref_weight_g;
|
||||
$foodProduct->nv_kj = $request->nv_kj;
|
||||
$foodProduct->nv_kcal = $request->nv_kcal;
|
||||
$foodProduct->nv_fat_g = $request->nv_fat_g;
|
||||
$foodProduct->nv_sat_fat_g = $request->nv_sat_fat_g;
|
||||
$foodProduct->nv_carb_g = $request->nv_carb_g;
|
||||
$foodProduct->nv_sugar_g = $request->nv_sugar_g;
|
||||
$foodProduct->nv_fiber_g = $request->nv_fiber_g;
|
||||
$foodProduct->nv_protein_g = $request->nv_protein_g;
|
||||
$foodProduct->nv_salt_g = $request->nv_salt_g;
|
||||
$foodProduct->nv_serving_size_g = $request->nv_serving_size_g;
|
||||
$foodProduct->nv_serving_kj = $request->nv_serving_kj;
|
||||
$foodProduct->nv_serving_kcal = $request->nv_serving_kcal;
|
||||
$foodProduct->nv_serving_fat_g = $request->nv_serving_fat_g;
|
||||
$foodProduct->nv_serving_sat_fat_g = $request->nv_serving_sat_fat_g;
|
||||
$foodProduct->nv_serving_carb_g = $request->nv_serving_carb_g;
|
||||
$foodProduct->nv_serving_sugar_g = $request->nv_serving_sugar_g;
|
||||
$foodProduct->nv_serving_fiber_g = $request->nv_serving_fiber_g;
|
||||
$foodProduct->nv_serving_protein_g = $request->nv_serving_protein_g;
|
||||
$foodProduct->nv_serving_salt_g = $request->nv_serving_salt_g;
|
||||
$foodProduct->nv_daily_energy = $request->nv_daily_energy;
|
||||
$foodProduct->nv_daily_fat = $request->nv_daily_fat;
|
||||
$foodProduct->nv_daily_sat_fat = $request->nv_daily_sat_fat;
|
||||
$foodProduct->nv_daily_carb = $request->nv_daily_carb;
|
||||
$foodProduct->nv_daily_sugar = $request->nv_daily_sugar;
|
||||
$foodProduct->nv_daily_fiber = $request->nv_daily_fiber;
|
||||
$foodProduct->nv_daily_protein = $request->nv_daily_protein;
|
||||
$foodProduct->nv_daily_salt = $request->nv_daily_salt;
|
||||
$foodProduct->nutriscore = $request->nutriscore;
|
||||
$foodProduct->nutriscore_args = $request->nutriscore_args;
|
||||
|
||||
$foodProduct->product_id = $product_id;
|
||||
|
||||
|
||||
$foodProduct->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* helper method to update toolproduct info
|
||||
*
|
||||
* @param Request $request
|
||||
* @param integer $product_id
|
||||
* @return void
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
*/
|
||||
public function saveToolProduct(Request $request, int $product_id)
|
||||
{
|
||||
// phpcs:enable
|
||||
$toolProduct = ToolProduct::firstOrNew([
|
||||
'product_id' => $product_id,
|
||||
]);
|
||||
|
||||
$toolProduct->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* helper method to update anifoodProduct info
|
||||
*
|
||||
* @param Request $request
|
||||
* @param integer $product_id
|
||||
* @return void
|
||||
*/
|
||||
public function saveAnifoodProduct(Request $request, int $product_id)
|
||||
{
|
||||
$anifoodProduct = AnifoodProduct::firstOrNew([
|
||||
'product_id' => $product_id,
|
||||
]);
|
||||
|
||||
$anifoodProduct->composition = $request->composition;
|
||||
$anifoodProduct->servings = $request->servings;
|
||||
$anifoodProduct->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* helper method to update garmentProduct info
|
||||
*
|
||||
* @param Request $request
|
||||
* @param integer $product_id
|
||||
* @return void
|
||||
*/
|
||||
public function saveGarmentProduct(Request $request, int $product_id)
|
||||
{
|
||||
$garmentProduct = GarmentProduct::firstOrNew([
|
||||
'product_id' => $product_id,
|
||||
]);
|
||||
|
||||
$garmentProduct->size = $request->size;
|
||||
$garmentProduct->color = $request->color;
|
||||
$garmentProduct->material = $request->material;
|
||||
$garmentProduct->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* index des produits mis en avant
|
||||
*
|
||||
* @return * @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function starred()
|
||||
{
|
||||
$products = Product::where('star', 1)->paginate(10);
|
||||
return view('bo.products.starred', compact('products'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\DiscountType;
|
||||
use App\Models\Promotion;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PromotionsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$promotions = Promotion::all();
|
||||
return view('bo.promotions.index', compact('promotions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$discTypes = DiscountType::all();
|
||||
|
||||
$existingProds = Product::all();
|
||||
$promotion = new Promotion();
|
||||
$selectedProds = $promotion->products;
|
||||
return view('bo.promotions.create', compact('discTypes', 'existingProds', 'selectedProds'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
|
||||
$request->validate([
|
||||
'product_id' => 'required',
|
||||
]);
|
||||
|
||||
$productIds = explode(",", $request->product_id);
|
||||
$discType = $request->discount_type_id;
|
||||
$value = $request->discount_value;
|
||||
$date_start = $request->date_start_date . " " . $request->date_start_time;
|
||||
$date_end = $request->date_end_date . " " . $request->date_end_time;
|
||||
|
||||
$promotion = new Promotion();
|
||||
$promotion->discount_type_id = $discType;
|
||||
$promotion->discount_value = $value;
|
||||
$promotion->date_start = $date_start;
|
||||
$promotion->date_end = $date_end;
|
||||
$promotion->save();
|
||||
|
||||
// Prise en charge de la liaison avec les produits.
|
||||
$promotion->products()->sync($productIds);
|
||||
|
||||
return redirect()->route('bo.promotions.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$promotion = Promotion::findOrFail($id);
|
||||
$discTypes = DiscountType::all();
|
||||
|
||||
$existingProds = Product::all();
|
||||
$selectedProds = $promotion->products;
|
||||
$existingProds = $existingProds->diff($selectedProds);
|
||||
|
||||
return view('bo.promotions.edit', compact('promotion', 'discTypes', 'existingProds', 'selectedProds'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$promotion = Promotion::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'product_id' => 'required',
|
||||
]);
|
||||
|
||||
$productIds = explode(",", $request->product_id);
|
||||
$discType = $request->discount_type_id;
|
||||
$value = $request->discount_value;
|
||||
$date_start = $request->date_start_date . " " . $request->date_start_time;
|
||||
$date_end = $request->date_end_date . " " . $request->date_end_time;
|
||||
|
||||
$promotion->discount_type_id = $discType;
|
||||
$promotion->discount_value = $value;
|
||||
$promotion->date_start = $date_start;
|
||||
$promotion->date_end = $date_end;
|
||||
$promotion->save();
|
||||
|
||||
// Prise en charge de la liaison avec les produits.
|
||||
$promotion->products()->sync($productIds);
|
||||
|
||||
return redirect()->route('bo.promotions.edit', $promotion->id)->with('success', 'Modifications enregistrés !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$p = Promotion::findOrFail($id);
|
||||
|
||||
// Prise en charge de la liaison avec les produits.
|
||||
$p->products()->detach();
|
||||
|
||||
$p->delete();
|
||||
|
||||
return redirect()->route('bo.promotions.index');
|
||||
}
|
||||
}
|
||||
141
app/Http/Controllers/Bo/RangeController.php
Normal file
141
app/Http/Controllers/Bo/RangeController.php
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Ranges\StoreRangeRequest;
|
||||
use App\Http\Requests\Bo\Ranges\UpdateRangeRequest;
|
||||
use App\Models\Merchandise\Range;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RangeController extends Controller
|
||||
{
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $ranges */
|
||||
$ranges = Range::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$ranges,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
'description'
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($ranges);
|
||||
$searchFields = trans('Nom, Description');
|
||||
|
||||
$ranges->orderBy('updated_at', 'DESC');
|
||||
$ranges = $ranges->paginate();
|
||||
|
||||
return view('back::pages.ranges.index', compact('ranges', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('back::pages.ranges.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Ranges\StoreRangeRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreRangeRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$range = new Range();
|
||||
$range->fill($request->validated());
|
||||
|
||||
if ($range->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.ranges.edit', $range)
|
||||
->with('bo.success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Range $range
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Range $range)
|
||||
{
|
||||
return view('back::pages.ranges.edit', [
|
||||
'rangeModel' => $range
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Ranges\UpdateRangeRequest $request
|
||||
* @param \App\Models\Merchandise\Range $range
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateRangeRequest $request, Range $range)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $range) {
|
||||
$range->fill($request->validated());
|
||||
if ($range->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.ranges.edit', $range)
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
} //end if
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Range $range
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Range $range)
|
||||
{
|
||||
if ($range->products()->count() > 0) {
|
||||
return redirect()->back()
|
||||
->withErrors("Suppression impossible : {$range->id} {$range->name} contient encore des produits.");
|
||||
}
|
||||
|
||||
if ($range->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.ranges.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.ranges'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\OldSlug;
|
||||
use App\Models\Product;
|
||||
use App\Models\Range;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RangesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$ranges = Range::all();
|
||||
return view('bo.ranges.index', compact('ranges'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.ranges.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$name = $request->name;
|
||||
$slug = Str::slug($name);
|
||||
$description = $request->description;
|
||||
$picture = $request->picture;
|
||||
$status = $request->status === null ? 0 : 1;
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'required',
|
||||
'picture' => 'image|mimes:jpeg,png,jpg|max:2048|dimensions:max-width=' .
|
||||
config('theme.range_image_maxwidth') . ',max-height=' .
|
||||
config('theme.range_image_maxheight'),
|
||||
]);
|
||||
|
||||
$range = new Range();
|
||||
$range->name = $name;
|
||||
$range->slug = $slug;
|
||||
$range->description = $description;
|
||||
$range->status = $status;
|
||||
$range->save();
|
||||
|
||||
if ($picture !== null) {
|
||||
$imageName = $range->id . '_' . $slug . '_' . Str::random(5) . '.' . $picture->extension();
|
||||
$picture->move(public_path('images/gammes'), $imageName);
|
||||
$range->picture = $imageName;
|
||||
$range->save();
|
||||
}
|
||||
|
||||
return redirect()->route('bo.ranges.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$range = Range::findOrFail($id);
|
||||
return view('bo.ranges.edit', compact('range'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$name = $request->name;
|
||||
$slug = Str::slug($name);
|
||||
$description = $request->description;
|
||||
$picture = $request->picture;
|
||||
$status = $request->status === null ? 0 : 1;
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'required',
|
||||
'picture' => 'image|mimes:jpeg,png,jpg|max:2048|dimensions:max-width=' .
|
||||
config('theme.range_image_maxwidth') . ',max-height=' .
|
||||
config('theme.range_image_maxheight'),
|
||||
]);
|
||||
|
||||
$range = Range::findOrFail($id);
|
||||
|
||||
if ($picture !== null) {
|
||||
if ($range->picture !== null && file_exists(public_path('images/gammes/') . $range->picture)) {
|
||||
unlink(public_path('images/gammes/') . $range->picture);
|
||||
}
|
||||
$imageName = $range->id . '_' . $slug . '_' . Str::random(5) . '.' . $picture->extension();
|
||||
$picture->move(public_path('images/gammes'), $imageName);
|
||||
}
|
||||
|
||||
$range->name = $name;
|
||||
|
||||
if ($range->slug != $slug) {
|
||||
$exist = OldSlug::where('slug', $range->slug)->first();
|
||||
if ($exist === null) {
|
||||
$oldSlug = new OldSlug();
|
||||
$oldSlug->range_id = $range->id;
|
||||
$oldSlug->slug = $range->slug;
|
||||
$oldSlug->save();
|
||||
}
|
||||
}
|
||||
|
||||
$range->slug = $slug;
|
||||
$range->description = $description;
|
||||
if ($picture !== null) {
|
||||
$range->picture = $imageName;
|
||||
}
|
||||
$range->status = $status;
|
||||
$range->save();
|
||||
|
||||
return redirect()->route('bo.ranges.edit', $range->id)->with('success', 'Modifications enregistrés !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$range = Range::findOrFail($id);
|
||||
|
||||
$product = Product::where('range_id', $range->id)->count();
|
||||
if ($product !== 0) {
|
||||
return redirect()->back()
|
||||
->withErrors("Suppression impossible : \"" . $range->name . "\" contient encore des produits.");
|
||||
}
|
||||
|
||||
if ($range->picture !== null) {
|
||||
if (file_exists(public_path('images/gammes/') . $range->picture)) {
|
||||
unlink(public_path('images/gammes/') . $range->picture);
|
||||
}
|
||||
}
|
||||
|
||||
OldSlug::where('range_id', $range->id)->delete();
|
||||
|
||||
$range->delete();
|
||||
return redirect()->route('bo.ranges.index');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Manage settings page
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
*/
|
||||
public function manage(Request $request)
|
||||
{
|
||||
$settings = Setting::all();
|
||||
$settingsToPrint = [];
|
||||
foreach ($settings as $setting) {
|
||||
$settingsToPrint[$setting->key] = $setting->value;
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$input = $request->all();
|
||||
|
||||
// Comparer les settingsToPrint (en base) avec les inputs (pour trouver un nouveau).
|
||||
foreach ($input as $key => $value) {
|
||||
if (
|
||||
!isset($settingsToPrint[$key])
|
||||
&& $key != "_method"
|
||||
&& $key != "_token"
|
||||
) {
|
||||
// New setting.
|
||||
$setting = new Setting();
|
||||
$setting->key = $key;
|
||||
$setting->value = $value ?? 0;
|
||||
$setting->save();
|
||||
}
|
||||
}
|
||||
|
||||
$looplimit = count($settings);
|
||||
for ($i = 0; $i < $looplimit; $i++) {
|
||||
if (is_array($request->input($settings[$i]->key))) {
|
||||
$settings[$i]->value = implode(',', $request->input($settings[$i]->key));
|
||||
} else {
|
||||
$settings[$i]->value = $request->input($settings[$i]->key) === null ? 0
|
||||
: $request->input($settings[$i]->key);
|
||||
}
|
||||
$settings[$i]->save();
|
||||
}
|
||||
|
||||
// Store redirector to keep flash message from being wipe pby artisan call below.
|
||||
$redirector = redirect()->route('bo.settings')->with('success', 'Modifications enregistrés !');
|
||||
|
||||
// All settings saved : cache routes.
|
||||
Artisan::call('route:clear');
|
||||
// Programmer un php artisan optimize ? (une fois par jour la nuit par exemple).
|
||||
return $redirector;
|
||||
}//end if
|
||||
|
||||
return view('bo.settings', compact('settingsToPrint'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage Theme settings page
|
||||
* Management des settings dont la clé est préfixée theme_
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
*/
|
||||
public function manageTheme(Request $request)
|
||||
{
|
||||
$settings = Setting::where('key', 'LIKE', 'theme_%')->get();
|
||||
$settingsToPrint = [];
|
||||
foreach ($settings as $setting) {
|
||||
$settingsToPrint[$setting->key] = $setting->value;
|
||||
}
|
||||
|
||||
$config_settings = Config::get(('theme.bo_theme_settings'));
|
||||
|
||||
// Check if, for each of the theme defined settings we have a database setting.
|
||||
foreach ($config_settings as $onekey => $params) {
|
||||
if (!isset($settingsToPrint['theme_' . $onekey])) {
|
||||
$dbsetting = new Setting();
|
||||
$dbsetting->key = 'theme_' . $onekey;
|
||||
$dbsetting->value = $params['default_value'];
|
||||
$dbsetting->save();
|
||||
// Injection dans settings to print.
|
||||
$settingsToPrint[$dbsetting->key] = $dbsetting->value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$looplimit = count($settings);
|
||||
for ($i = 0; $i < $looplimit; $i++) {
|
||||
// Attention pour les booléens/checkbox on enregistre 'on'.
|
||||
$settings[$i]->value = $request->input($settings[$i]->key) === null ? 0
|
||||
: $request->input($settings[$i]->key);
|
||||
$settings[$i]->save();
|
||||
}
|
||||
return redirect()->route('bo.themesettings')->with('success', 'Modifications enregistrés !');
|
||||
}
|
||||
|
||||
return view('bo.settings.theme', compact('settingsToPrint', 'config_settings'));
|
||||
}
|
||||
}
|
||||
197
app/Http/Controllers/Bo/ShopController.php
Normal file
197
app/Http/Controllers/Bo/ShopController.php
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Ajax\TimeslotExceptions\DeleteTimeslotExceptionsRequest;
|
||||
use App\Http\Requests\Bo\Ajax\TimeslotExceptions\SaveTimeslotExceptionsRequest;
|
||||
use App\Http\Requests\Bo\Shops\StoreShopRequest;
|
||||
use App\Http\Requests\Bo\Shops\UpdateShopRequest;
|
||||
use App\Models\Shop\CollectionException;
|
||||
use App\Models\Shop\Shop;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ShopController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $shops */
|
||||
$shops = Shop::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$shops,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
'address',
|
||||
'city',
|
||||
'postal_code'
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($shops);
|
||||
$searchFields = trans('Nom, adresse, ville, cp');
|
||||
|
||||
$shops->orderBy('updated_at', 'DESC');
|
||||
$shops = $shops->paginate();
|
||||
|
||||
return view('back::pages.shops.index', compact('shops', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('back::pages.shops.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Shops \StoreShopRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreShopRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$shop = new Shop();
|
||||
$shop->fill($request->validated());
|
||||
|
||||
if ($shop->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.shops.edit', $shop)
|
||||
->with('bo.success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.shops'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Shop\Shop $shop
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Shop $shop)
|
||||
{
|
||||
$exceptionsCollecte = $shop->collectionExceptions()->orderBy('date')->get();
|
||||
return view('back::pages.shops.edit', [
|
||||
'shopModel' => $shop,
|
||||
'exceptionsCollecte' => $exceptionsCollecte
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Shops\UpdateShopRequest $request
|
||||
* @param \App\Models\Shop\Shop $shop
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateShopRequest $request, Shop $shop)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $shop) {
|
||||
$shop->fill($request->validated());
|
||||
if ($shop->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.shops.edit', $shop)
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.shops'))]
|
||||
));
|
||||
} //end if
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Shop\Shop $shop
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Shop $shop)
|
||||
{
|
||||
if (Shop::count() <= 1) {
|
||||
return redirect()->back()
|
||||
->withErrors('Suppression impossible : Vous devez conserver au moins 1 point de retrait.');
|
||||
}
|
||||
if ($shop->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.shops.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.shops'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save collect exceptions
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Ajax\TimeslotExceptions\SaveTimeslotExceptionsRequest $request
|
||||
* @param \App\Models\Shop\Shop $shop
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function saveExceptions(SaveTimeslotExceptionsRequest $request, Shop $shop): JsonResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $shop) {
|
||||
$collecteExceptionDates = \collect($request->dates)->keyBy('date');
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Shop\CollectionException> */
|
||||
$collectionExceptions = $shop->collectionExceptions
|
||||
->filter(function (CollectionException $collectionException) use ($collecteExceptionDates) {
|
||||
if (!$collecteExceptionDates->has($collectionException->date->format('Y-m-d'))) {
|
||||
$collectionException->deleteOrFail();
|
||||
return false;
|
||||
}
|
||||
$collecteExceptionDates->pull($collectionException->date->format('Y-m-d'));
|
||||
return true;
|
||||
});
|
||||
$collecteExceptionDates->map(function (array $ajaxCollectionexception) use ($shop, $collectionExceptions) {
|
||||
$collectionException = new CollectionException($ajaxCollectionexception);
|
||||
$collectionException->shop()->associate($shop);
|
||||
$collectionException->saveOrFail();
|
||||
$collectionException->refresh();
|
||||
$collectionExceptions->push($collectionException);
|
||||
});
|
||||
return \response()->json($collectionExceptions);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* delete collecte exception
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Ajax\TimeslotExceptions\DeleteTimeslotExceptionsRequest $request
|
||||
* @param \App\Models\Shop\Shop $shop
|
||||
* @return string
|
||||
*/
|
||||
public function destroyExceptions(DeleteTimeslotExceptionsRequest $request, Shop $shop): JsonResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $shop) {
|
||||
CollectionException::whereHas('shop', function (Builder $q) use ($shop) {
|
||||
$q->where('id', $shop->id);
|
||||
})->whereId($request->id)->firstOrFail()->deleteOrFail();
|
||||
|
||||
return \response()->json($shop->collectionExceptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
136
app/Http/Controllers/Bo/SlideController.php
Normal file
136
app/Http/Controllers/Bo/SlideController.php
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Slides\StoreSlideRequest;
|
||||
use App\Http\Requests\Bo\Slides\UpdateSlideRequest;
|
||||
use App\Models\Site\Slide;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SlideController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $slides */
|
||||
$slides = Slide::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$slides,
|
||||
$request->search,
|
||||
null,
|
||||
'title'
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($slides);
|
||||
$searchFields = trans('Titre');
|
||||
|
||||
$slides->orderBy('updated_at', 'DESC');
|
||||
$slides = $slides->paginate();
|
||||
|
||||
return view('back::pages.slides.index', compact('slides', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('back::pages.slides.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Slides\StoreSlideRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreSlideRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$slide = new Slide();
|
||||
$slide->fill($request->validated());
|
||||
$slide->order = Slide::query()->orderBy('order', 'DESC')->limit(1)->value('order') ?? 0;
|
||||
|
||||
if ($slide->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.slides.edit', $slide)
|
||||
->with('bo.success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.slides'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Site\Slide $slide
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Slide $slide)
|
||||
{
|
||||
return view('back::pages.slides.edit', [
|
||||
'slideModel' => $slide
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Slides\UpdateSlideRequest $request
|
||||
* @param \App\Models\Site\Slide $slide
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateSlideRequest $request, Slide $slide)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $slide) {
|
||||
$slide->fill($request->validated());
|
||||
if ($slide->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.slides.edit', $slide)
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.slides'))]
|
||||
));
|
||||
} //end if
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Site\Slide $slide
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Slide $slide)
|
||||
{
|
||||
if ($slide->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.slides.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.slides'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Slider;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SlidersController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$sliders = Slider::all();
|
||||
return view('bo.sliders.index', compact('sliders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.sliders.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$label = $request->label;
|
||||
$slug = $request->slug;
|
||||
if (empty($slug)) {
|
||||
$slug = Str::slug($label);
|
||||
}
|
||||
$commentaire = $request->commentaire;
|
||||
|
||||
|
||||
$request->validate([
|
||||
'label' => 'required|string|max:255',
|
||||
'slug' => 'sometimes|unique:sliders',
|
||||
]);
|
||||
|
||||
$slider = new Slider();
|
||||
$slider->label = $label;
|
||||
$slider->slug = $slug;
|
||||
$slider->commentaire = $commentaire;
|
||||
$slider->save();
|
||||
return redirect()->route('bo.sliders.edit', $slider->id)->with('success', 'Slider créé !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$slider = Slider::findOrFail($id);
|
||||
return view('bo.sliders.edit', compact('slider'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$slider = Slider::findOrFail($id);
|
||||
$label = $request->label;
|
||||
$slug = $request->slug;
|
||||
$commentaire = $request->commentaire;
|
||||
|
||||
|
||||
$request->validate([
|
||||
'label' => 'required|string|max:255',
|
||||
'slug' => 'required|unique:sliders,slug,' . $slider->id,
|
||||
]);
|
||||
|
||||
$slider->label = $label;
|
||||
$slider->slug = $slug;
|
||||
$slider->commentaire = $commentaire;
|
||||
$slider->save();
|
||||
|
||||
return redirect()->route('bo.sliders.edit', $slider->id)->with('success', 'Modifications enregistrées !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$slider = Slider::findOrFail($id);
|
||||
|
||||
$count = Slider::count();
|
||||
|
||||
if ($count === 1) {
|
||||
return redirect()->back()->withErrors("Suppression impossible : Vous devez conserver au moins 1 Slider");
|
||||
}
|
||||
$slider->delete();
|
||||
return redirect()->route('bo.sliders.index');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Slide;
|
||||
use App\Models\Slider;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SlidesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$slides = Slide::orderBy('order', 'ASC')->get();
|
||||
return view('bo.slides.index', compact('slides'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$sliders = Slider::all();
|
||||
return view('bo.slides.create', compact('sliders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$title = $request->title;
|
||||
$picture = $request->picture;
|
||||
$text = $request->text;
|
||||
$linkLabel = $request->link_label;
|
||||
$link = $request->link;
|
||||
$newTab = $request->link_new_tab === null ? 0 : 1;
|
||||
$sliderId = $request->slider_id;
|
||||
|
||||
if (empty($request->date_start_date)) {
|
||||
$date_start = null;
|
||||
} else {
|
||||
if (empty($request->date_start_time)) {
|
||||
$date_start = $request->date_start_date . " 00:00";
|
||||
} else {
|
||||
$date_start = $request->date_start_date . " " . $request->date_start_time;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($request->date_end_date)) {
|
||||
$date_end = null;
|
||||
} else {
|
||||
if (empty($request->date_end_time)) {
|
||||
$date_end = $request->date_end_date . " 23:59";
|
||||
} else {
|
||||
$date_end = $request->date_end_date . " " . $request->date_end_time;
|
||||
}
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'picture' => 'image|mimes:jpeg,png,jpg|max:2048|dimensions:max-width=' .
|
||||
config('theme.slide_image_maxwidth') . ',max-height=' .
|
||||
config('theme.slide_image_maxheight'),
|
||||
'link_label' => 'sometimes|max:255',
|
||||
'link' => 'sometimes|max:255',
|
||||
]);
|
||||
|
||||
$slide = new Slide();
|
||||
$slide->title = $title;
|
||||
$slide->text = $text;
|
||||
$slide->link_label = $linkLabel;
|
||||
$slide->link = $link;
|
||||
$slide->link_new_tab = $newTab;
|
||||
$slide->date_start = $date_start;
|
||||
$slide->date_end = $date_end;
|
||||
$slide->slider_id = $sliderId;
|
||||
$slide->order = $this->getLastOrder();
|
||||
$slide->save();
|
||||
|
||||
if ($picture !== null) {
|
||||
$imageName = $slide->id . '_' . Str::random(5) . '.' . $picture->extension();
|
||||
$picture->move(public_path('images/slides'), $imageName);
|
||||
$slide->picture = $imageName;
|
||||
$slide->save();
|
||||
}
|
||||
|
||||
return redirect()->route('bo.slides.edit', $slide->id)->with('success', 'Slide créé !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$slide = Slide::findOrFail($id);
|
||||
$sliders = Slider::all();
|
||||
return view('bo.slides.edit', compact('slide', 'sliders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$title = $request->title;
|
||||
$picture = $request->picture;
|
||||
$text = $request->text;
|
||||
$linkLabel = $request->link_label;
|
||||
$link = $request->link;
|
||||
$newTab = $request->link_new_tab === null ? 0 : 1;
|
||||
$sliderId = $request->slider_id;
|
||||
|
||||
if (empty($request->date_start_date)) {
|
||||
$date_start = null;
|
||||
} else {
|
||||
if (empty($request->date_start_time)) {
|
||||
$date_start = $request->date_start_date . " 00:00";
|
||||
} else {
|
||||
$date_start = $request->date_start_date . " " . $request->date_start_time;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($request->date_end_date)) {
|
||||
$date_end = null;
|
||||
} else {
|
||||
if (empty($request->date_end_time)) {
|
||||
$date_end = $request->date_end_date . " 23:59";
|
||||
} else {
|
||||
$date_end = $request->date_end_date . " " . $request->date_end_time;
|
||||
}
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'picture' => 'image|mimes:jpeg,png,jpg|max:2048|dimensions:max-width=' .
|
||||
config('theme.slide_image_maxwidth') . ',max-height=' .
|
||||
config('theme.slide_image_maxheight'),
|
||||
'link_label' => 'sometimes|max:255',
|
||||
'link' => 'sometimes|max:255',
|
||||
]);
|
||||
|
||||
$slide = Slide::findOrFail($id);
|
||||
$slide->title = $title;
|
||||
$slide->text = $text;
|
||||
$slide->link_label = $linkLabel;
|
||||
$slide->link = $link;
|
||||
$slide->link_new_tab = $newTab;
|
||||
$slide->date_start = $date_start;
|
||||
$slide->date_end = $date_end;
|
||||
$slide->slider_id = $sliderId;
|
||||
$slide->save();
|
||||
|
||||
if ($picture !== null) {
|
||||
if (file_exists(public_path() . 'images/slides/' . $slide->picture)) {
|
||||
unlink(public_path() . 'images/slides/' . $slide->picture);
|
||||
}
|
||||
$imageName = $slide->id . '_' . Str::random(5) . '.' . $picture->extension();
|
||||
$picture->move(public_path('images/slides'), $imageName);
|
||||
$slide->picture = $imageName;
|
||||
$slide->save();
|
||||
}
|
||||
|
||||
return redirect()->route('bo.slides.edit', $slide->id)->with('success', 'Modifications enregistrées !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$s = Slide::findOrFail($id);
|
||||
|
||||
$s->delete();
|
||||
|
||||
return redirect()->route('bo.slides.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Slide Order
|
||||
*
|
||||
* @param integer $id
|
||||
* @param string $action
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function changeOrder(int $id, string $action)
|
||||
{
|
||||
$current = Slide::findOrFail($id);
|
||||
|
||||
if ($action === 'up') {
|
||||
$tmp = Slide::where('order', '<', $current->order)->orderBy('order', 'DESC')->first();
|
||||
$newOrder = $tmp->order;
|
||||
$tmp->order = $current->order;
|
||||
$current->order = $newOrder;
|
||||
} else {
|
||||
$tmp = Slide::where('order', '>', $current->order)->orderBy('order', 'ASC')->first();
|
||||
$newOrder = $tmp->order;
|
||||
$tmp->order = $current->order;
|
||||
$current->order = $newOrder;
|
||||
}
|
||||
$tmp->save();
|
||||
$current->save();
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* retreive order position to put a new slide to
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
private function getLastOrder()
|
||||
{
|
||||
$order = Slide::select('order')->orderBy('order', 'DESC')->first();
|
||||
if ($order === null) {
|
||||
return 1;
|
||||
}
|
||||
return $order->order + 1;
|
||||
}
|
||||
}
|
||||
149
app/Http/Controllers/Bo/StaticPageController.php
Normal file
149
app/Http/Controllers/Bo/StaticPageController.php
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\StaticPageType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\StaticPages\StoreStaticPageRequest;
|
||||
use App\Http\Requests\Bo\StaticPages\UpdateStaticPageRequest;
|
||||
use App\Models\Site\StaticPage;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StaticPageController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $static_pages */
|
||||
$static_pages = StaticPage::query()->where('type', '=', StaticPageType::crud());
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$static_pages,
|
||||
$request->search,
|
||||
null,
|
||||
'title',
|
||||
'value'
|
||||
);
|
||||
} //end if
|
||||
|
||||
$this->sortQuery($static_pages);
|
||||
$searchFields = trans('Titre, contenu');
|
||||
|
||||
$static_pages->orderBy('updated_at', 'DESC');
|
||||
$static_pages = $static_pages->paginate();
|
||||
|
||||
return view('back::pages.static_pages.index', compact('static_pages', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('back::pages.static_pages.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StaticPages\StoreStaticPageRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreStaticPageRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$static_page = new StaticPage();
|
||||
// * Only crud pages are allowed to be created.
|
||||
$static_page->type = StaticPageType::crud();
|
||||
$static_page->fill($request->validated());
|
||||
|
||||
if ($static_page->saveOrFail()) {
|
||||
return redirect()
|
||||
->to(
|
||||
\App\Models\Site\StaticPage::getBoRouteForType($static_page->type, 'edit') ??
|
||||
route('bo.static_pages.edit', $static_page->id)
|
||||
)
|
||||
->with('bo.success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.static_pages'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Site\StaticPage $static_page
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(StaticPage $static_page)
|
||||
{
|
||||
return view('back::pages.static_pages.edit', ['static_pageModel' => $static_page]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\StaticPages\UpdateStaticPageRequest $request
|
||||
* @param \App\Models\Site\StaticPage $static_page
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateStaticPageRequest $request, StaticPage $static_page)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $static_page) {
|
||||
try {
|
||||
$static_page->fill($request->validated());
|
||||
} catch (\ErrorException $e) {
|
||||
return back()
|
||||
->with('bo.danger', trans(
|
||||
':model n\'a pas pu être enregistré car l\'image n\'a pu être transférée.',
|
||||
['model' => Str::singular(trans('models.classes.pages'))]
|
||||
));
|
||||
}
|
||||
|
||||
if ($static_page->saveOrFail()) {
|
||||
return redirect()
|
||||
->to(
|
||||
\App\Models\Site\StaticPage::getBoRouteForType($static_page->type, 'edit') ??
|
||||
route('bo.static_pages.edit', $static_page->id)
|
||||
)
|
||||
->with('bo.success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => trans('Page')]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Site\StaticPage $static_page
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(StaticPage $static_page)
|
||||
{
|
||||
if ($static_page->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.static_pages.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.static_pages'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
}
|
||||
154
app/Http/Controllers/Bo/TagController.php
Normal file
154
app/Http/Controllers/Bo/TagController.php
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Tags\StoreTagRequest;
|
||||
use App\Http\Requests\Bo\Tags\UpdateTagRequest;
|
||||
use App\Models\Merchandise\Tag;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $tags */
|
||||
$tags = Tag::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$tags,
|
||||
$request->search,
|
||||
null,
|
||||
'label'
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortQuery($tags);
|
||||
$searchFields = trans('Label');
|
||||
|
||||
$tags = $tags->paginate();
|
||||
|
||||
return view('back::pages.tags.index', compact('tags', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('back::pages.tags.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Tags\StoreTagRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreTagRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$tag = new Tag();
|
||||
$tag->fill($request->validated());
|
||||
|
||||
if ($tag->saveOrFail()) {
|
||||
$tag->products()->sync($request->product_list);
|
||||
return redirect()
|
||||
->route('bo.tags.edit', $tag)
|
||||
->with('bo.success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Tags\StoreTagRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function jsonStore(StoreTagRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
/** @var \App\Models\Merchandise\Tag */
|
||||
$tag = Tag::where('slug', Str::slug($request->name))->firstOrNew();
|
||||
$tag->fill($request->validated());
|
||||
$saved = $tag->saveOrFail();
|
||||
return \response()->json($saved ? $tag->toArray() : [], $saved ? 200 : 500);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Tag $tag
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Tag $tag)
|
||||
{
|
||||
return view('back::pages.tags.edit', ['tagModel' => $tag]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Tags\UpdateTagRequest $request
|
||||
* @param \App\Models\Merchandise\Tag $tag
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UpdateTagRequest $request, Tag $tag)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $tag) {
|
||||
$tag->fill($request->validated());
|
||||
$tag->products()->sync($request->product_list);
|
||||
|
||||
if ($tag->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.tags.edit', $tag)
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
));
|
||||
} //end if
|
||||
return back();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Tag $tag
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Tag $tag)
|
||||
{
|
||||
if ($tag->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.tags.index')
|
||||
->with('bo.warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
));
|
||||
}
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class TagsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$tags = Tag::orderBy('order', 'ASC')->get();
|
||||
return view('bo.tags.index', compact('tags'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('bo.tags.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$label = $request->label;
|
||||
$slug = Str::slug($label);
|
||||
$status = $request->status === null ? 0 : 1;
|
||||
|
||||
$request->validate([
|
||||
'label' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$tag = new Tag();
|
||||
$tag->label = $label;
|
||||
$tag->slug = $slug;
|
||||
$tag->status = $status;
|
||||
$tag->order = $this->getLastOrder();
|
||||
$tag->save();
|
||||
|
||||
return redirect()->route('bo.tags.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$tag = Tag::findOrFail($id);
|
||||
return view('bo.tags.edit', compact('tag'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$label = $request->label;
|
||||
$slug = Str::slug($label);
|
||||
$status = $request->status === null ? 0 : 1;
|
||||
|
||||
$request->validate([
|
||||
'label' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$tag = Tag::findOrFail($id);
|
||||
|
||||
$tag->label = $label;
|
||||
$tag->slug = $slug;
|
||||
$tag->status = $status;
|
||||
$tag->save();
|
||||
|
||||
return redirect()->route('bo.tags.edit', $tag->id)->with('success', 'Modifications enregistrés !');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$tag = Tag::findOrFail($id);
|
||||
|
||||
$products = $tag->products()->count();
|
||||
if ($products !== 0) {
|
||||
return redirect()->back()
|
||||
->withErrors("Suppression impossible : \"" . $tag->label . "\" est associé à des produits.");
|
||||
}
|
||||
|
||||
$tag->delete();
|
||||
return redirect()->route('bo.tags.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Tag Order
|
||||
*
|
||||
* @param integer $id
|
||||
* @param string $action
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function changeOrder(int $id, string $action)
|
||||
{
|
||||
$current = Tag::findOrFail($id);
|
||||
|
||||
if ($action === 'up') {
|
||||
$tmp = Tag::where('order', '<', $current->order)->orderBy('order', 'DESC')->first();
|
||||
$newOrder = $tmp->order;
|
||||
$tmp->order = $current->order;
|
||||
$current->order = $newOrder;
|
||||
} else {
|
||||
$tmp = Tag::where('order', '>', $current->order)->orderBy('order', 'ASC')->first();
|
||||
$newOrder = $tmp->order;
|
||||
$tmp->order = $current->order;
|
||||
$current->order = $newOrder;
|
||||
}
|
||||
$tmp->save();
|
||||
$current->save();
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle tag status
|
||||
*
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function toggleStatus(int $id)
|
||||
{
|
||||
$tag = Tag::findOrFail($id);
|
||||
$tag->status = !($tag->status);
|
||||
$tag->save();
|
||||
return back();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* retreive order position to put a new slide to
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function getLastOrder()
|
||||
{
|
||||
$order = Tag::select('order')->orderBy('order', 'DESC')->first();
|
||||
if ($order === null) {
|
||||
return 1;
|
||||
}
|
||||
return $order->order + 1;
|
||||
}
|
||||
}
|
||||
56
app/Http/Controllers/Bo/TimeslotController.php
Normal file
56
app/Http/Controllers/Bo/TimeslotController.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\TimeSlot\WeekDay;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Timeslots\UpdateTimeslotRequest;
|
||||
use App\Models\Shop\Shop;
|
||||
use App\Models\Shop\TimeslotSetting;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class TimeslotController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display timeslot settings form
|
||||
*
|
||||
* @param \App\Models\Shop\Shop $shop
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function settings(Shop $shop)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Shop\TimeslotSetting> */
|
||||
$timeslotSettings = $shop->timeslotSettings;
|
||||
|
||||
return view('back::pages.timeslots.settings', [
|
||||
'timeslotSettings' => $timeslotSettings,
|
||||
'shopModel' => $shop
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* save settings
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Timeslots\UpdateTimeslotRequest $request
|
||||
* @param \App\Models\Shop\Shop $shop
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function updateSettings(UpdateTimeslotRequest $request, Shop $shop)
|
||||
{
|
||||
return DB::transaction(function () use ($request, $shop) {
|
||||
$validated = $request->validated()['plages'];
|
||||
foreach (WeekDay::toArray() as $weekDay) {
|
||||
$setting = TimeslotSetting::where('day', $weekDay)
|
||||
->whereHas('shop', function (Builder $q) use ($shop) {
|
||||
$q->where('id', $shop->id);
|
||||
})->firstOrFail();
|
||||
$setting->fill($validated[$weekDay->value]);
|
||||
$setting->saveOrFail();
|
||||
}
|
||||
|
||||
return redirect()->route('bo.timeslots.settings', $shop)
|
||||
->with('bo.success', 'Modifications enregistrées !');
|
||||
});
|
||||
}
|
||||
}
|
||||
63
app/Http/Controllers/Bo/XmlIncoController.php
Normal file
63
app/Http/Controllers/Bo/XmlIncoController.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\XmlIncos\SearchXmlInco;
|
||||
use App\Http\Resources\XmlIncoCollection;
|
||||
use App\Models\XmlInco;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Kwaadpepper\ImageResizer\ImageResizer;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
class XmlIncoController extends Controller
|
||||
{
|
||||
/**
|
||||
* Download a file from inco storage.
|
||||
*
|
||||
* @param string $inco_picture
|
||||
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
||||
*/
|
||||
public function getXmlIncoPicture(string $inco_picture): StreamedResponse
|
||||
{
|
||||
if (!($picturePath = XmlInco::getXmlIncoPicturePath($inco_picture))) {
|
||||
abort(404);
|
||||
}
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||
$disk = XmlInco::getDisk();
|
||||
|
||||
// * Resized inco picture if wanted.
|
||||
if (request()->get('resize')) {
|
||||
$resizedPath = ImageResizer::resizeImageOrIgnore(
|
||||
$disk->path($picturePath),
|
||||
'boIncoPicture'
|
||||
);
|
||||
$picturePath = $resizedPath ? $resizedPath : $picturePath;
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||
$disk = Storage::disk('public');
|
||||
}
|
||||
|
||||
return \response()->streamDownload(function () use ($disk, $picturePath) {
|
||||
$stream = $disk->readStream($picturePath);
|
||||
\fpassthru($stream);
|
||||
\fclose($stream);
|
||||
}, \pathinfo($inco_picture, \PATHINFO_BASENAME), [
|
||||
'Content-Type' => $disk->mimeType($picturePath),
|
||||
'Content-Length' => $disk->size($picturePath),
|
||||
'Content-Disposition' => 'inline',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for xml inco
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\XmlIncos\SearchXmlInco $request
|
||||
* @return \App\Http\Resources\XmlIncoCollection
|
||||
*/
|
||||
public function getXmlIncos(SearchXmlInco $request)
|
||||
{
|
||||
return new XmlIncoCollection(XmlInco::where('id', 'LIKE', "%$request->term%")
|
||||
->orWhere('descriptif', 'LIKE', "%$request->term%")
|
||||
->get());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\ContactFormRequest;
|
||||
use App\Mail\SendContactMail;
|
||||
use App\Models\Magasin;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Content;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* legal notice page
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function contact(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
$status = $request->session()->get('status');
|
||||
|
||||
// 1er magasin en base pour le moment
|
||||
$magasin = Magasin::first();
|
||||
$content = Content::where('key', 'contact')->first();
|
||||
|
||||
return view('contact', compact('status', 'magasin', 'content'));
|
||||
}
|
||||
|
||||
/**
|
||||
* submit contact form
|
||||
*
|
||||
* @param ContactFormRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function contactSubmit(ContactFormRequest $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
|
||||
$toMailSetting = Setting::where('key', 'send_contact_mail_to')->first();
|
||||
if (empty($toMailSetting->value)) {
|
||||
$toMail = config('mail.from.address');
|
||||
} else {
|
||||
$toMail = $toMailSetting->value;
|
||||
}
|
||||
// Envoi du mail d'alerte.
|
||||
Mail::to($toMail)->send(new SendContactMail($request));
|
||||
|
||||
return back()->with('status', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,14 +2,272 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\Order\TransactionType;
|
||||
use App\Models\Payment\Transaction;
|
||||
use App\Models\Shop\DeliveryMode;
|
||||
use App\Models\Shop\Order;
|
||||
use App\Models\Shop\PaymentMode;
|
||||
use Gloudemans\Shoppingcart\Cart;
|
||||
use Gloudemans\Shoppingcart\CartItem;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
use DispatchesJobs;
|
||||
use ValidatesRequests;
|
||||
|
||||
/**
|
||||
* Cart item options skel
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public static $cartItemOptionsSkel = [
|
||||
'virtual' => false,
|
||||
'reference' => '',
|
||||
'slug' => '',
|
||||
'picture' => '',
|
||||
'sell_unit' => '',
|
||||
'weight_with_unit' => '',
|
||||
// * Prix ttc du produit
|
||||
'price_ttc' => 0,
|
||||
// * Prix ttc du produit remisé
|
||||
'undiscounted_price_ttc' => 0,
|
||||
'tax_rate' => 0,
|
||||
'discount_type' => null,
|
||||
'discount_rate' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(function (Request $request, callable $next) {
|
||||
$reponse = $next($request);
|
||||
if (\request()->routeIs('bo.*') and !\request()->ajax()) {
|
||||
if (!DeliveryMode::getCached()->where('status', true)->count()) {
|
||||
Session::flash('bo.warning', trans('Aucun mode de livraison n\'est disponible'));
|
||||
}
|
||||
if (!PaymentMode::getCached()->where('status', true)->count()) {
|
||||
Session::flash('bo.warning', trans('Aucun mode de paiement n\'est disponible'));
|
||||
}
|
||||
}
|
||||
return $reponse;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Search query on specified fields
|
||||
* splitting search into words or using whole sentence
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
|
||||
* @param string $search The query string.
|
||||
* @param callable $searchQuery The query string.
|
||||
* @param string ...$fields Either a simple array or a string
|
||||
* in case of a string the two fields
|
||||
* would be concatenate to make the search.
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
protected function searchQuery(
|
||||
Builder $query,
|
||||
string $search,
|
||||
callable $searchQuery = null,
|
||||
string ...$fields
|
||||
): Builder {
|
||||
if (count($fields)) {
|
||||
// Search using words.
|
||||
$words = explode(' ', $search);
|
||||
$query->where(function ($query) use ($searchQuery, $words, $search, $fields) {
|
||||
foreach ($words as $word) {
|
||||
if (!strlen($word)) {
|
||||
continue;
|
||||
}
|
||||
$this->searchOnFields($query, $word, $fields);
|
||||
} //end foreach
|
||||
// Search whole using whole sentence.
|
||||
$this->searchOnFields($query, $search, $fields);
|
||||
if ($searchQuery) {
|
||||
$searchQuery($query);
|
||||
}
|
||||
});
|
||||
} //end if
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build query search on all fields
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param string $search
|
||||
* @param array $fields
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
private function searchOnFields(Builder $query, string $search, array $fields): Builder
|
||||
{
|
||||
$table = $query->getModel()->getTable();
|
||||
foreach ($fields as $f) {
|
||||
$f = str_replace('?', '\?', $f);
|
||||
if (is_array($f)) {
|
||||
$query->orWhereRaw(
|
||||
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($f)->map(function ($q) use ($table) {
|
||||
return "`$table`.`$q`";
|
||||
})->implode(', \' \', ')),
|
||||
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
|
||||
);
|
||||
} else {
|
||||
$query->orWhereRaw(
|
||||
"UPPER(`$table`.`$f`) LIKE UPPER(?)",
|
||||
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
|
||||
);
|
||||
}
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort columns with a query
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param array $ignore
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
protected function sortQuery(Builder $query, array $ignore = []): Builder
|
||||
{
|
||||
$rName = request()->route()->getName();
|
||||
$table = $query->getModel()->getTable();
|
||||
if (request()->sort_col) {
|
||||
Session::put("$rName.sort_col", request()->sort_col);
|
||||
Session::put("$rName.sorted", true);
|
||||
}
|
||||
if (request()->sort_way) {
|
||||
Session::put("$rName.sort_way", request()->sort_way);
|
||||
Session::put("$rName.sorted", true);
|
||||
}
|
||||
if (request()->rst) {
|
||||
Session::remove("$rName.sorted");
|
||||
Session::remove("$rName.sort_col");
|
||||
Session::remove("$rName.sort_way");
|
||||
}
|
||||
if (request()->sort_col and request()->sort_way and Schema::hasColumn($table, request()->sort_col)) {
|
||||
if (
|
||||
!isset($ignore) or
|
||||
(isset($ignore) and !in_array(request()->sort_col, $ignore))
|
||||
) {
|
||||
$query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->sort_way);
|
||||
}
|
||||
} elseif (Schema::hasColumn($table, 'order')) {
|
||||
$query = $query->orderBy('order', 'ASC');
|
||||
Session::put("$rName.sort_col", 'order');
|
||||
Session::put("$rName.sort_way", 'asc');
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter basket items to keep only the orderable ones
|
||||
*
|
||||
* ! Assert Model found, status true and orderable true.
|
||||
*
|
||||
* @param \Gloudemans\Shoppingcart\Cart $basket
|
||||
* @param array<string> $messages Will be filled with messages on warnings.
|
||||
* @return \Gloudemans\Shoppingcart\Cart
|
||||
*/
|
||||
protected function filterBasketKeepOnlyOrderableItems(Cart $basket, array &$messages = []): Cart
|
||||
{
|
||||
\collect($basket->content())->each(function (CartItem $item) use (&$basket, &$messages) {
|
||||
/** @var \App\Models\Merchandise\Product|null */
|
||||
$product = $item->model;
|
||||
if (!$product or (!$product and (!$product->status or !$product->orderable))) {
|
||||
$basket->remove($item->rowId);
|
||||
$messages[] = \trans(
|
||||
'Le produit :name a été retiré du panier car il n\'est plus disponible',
|
||||
[
|
||||
'name' => $item->name
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
return $basket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and download transaction invoice
|
||||
*
|
||||
* ! Appliable for both Fo and Bo controllers
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @param \App\Models\Payment\Transaction $transaction
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function downloadTransactionInvoice(Order $order, Transaction $transaction): Response
|
||||
{
|
||||
$this->authorize('download', $transaction);
|
||||
$title = trans('Commande du :date - :orderRef - :transRef', [
|
||||
'date' => $transaction->created_at->isoFormat('DD\/MM\/YYYY'),
|
||||
'orderRef' => $order->reference,
|
||||
'transRef' => $transaction->reference,
|
||||
]);
|
||||
$sluggedTitle = Str::slug(\implode(' ', [
|
||||
config('app.name'),
|
||||
$transaction->type->equals(TransactionType::debit()) ? trans('Facture') : trans('Avoir'),
|
||||
$transaction->created_at->isoFormat('YYYY-MM-DD'),
|
||||
]));
|
||||
return \response()->streamDownload(function () use ($transaction, $title) {
|
||||
echo $transaction->generateInvoice($title)->output();
|
||||
}, "{$sluggedTitle}.pdf", [
|
||||
'Cache-Control' => 'public, must-revalidate, max-age=0',
|
||||
'Content-Description' => 'File Transfer',
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Expires' => 'Sat, 26 Jul 1997 05:00:00 GMT',
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
|
||||
// For glory.
|
||||
'X-Generator' => 'mPDF'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and download transaction invoice
|
||||
*
|
||||
* ! Appliable for both Fo and Bo controllers
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function downloadOrderInvoice(Order $order): Response
|
||||
{
|
||||
$this->authorize('download', $order);
|
||||
$title = trans('Commande du :date - :orderRef - :transRef', [
|
||||
'date' => $order->created_at->isoFormat('DD\/MM\/YYYY'),
|
||||
'orderRef' => $order->reference,
|
||||
'transRef' => trans('Toutes transactions'),
|
||||
]);
|
||||
$sluggedTitle = Str::slug(\implode(' ', [
|
||||
config('app.name'),
|
||||
trans('Facture'),
|
||||
$order->created_at->isoFormat('YYYY-MM-DD'),
|
||||
]));
|
||||
return \response()->streamDownload(function () use ($order, $title) {
|
||||
echo $order->generateInvoice($title)->output();
|
||||
}, "{$sluggedTitle}.pdf", [
|
||||
'Cache-Control' => 'public, must-revalidate, max-age=0',
|
||||
'Content-Description' => 'File Transfer',
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Expires' => 'Sat, 26 Jul 1997 05:00:00 GMT',
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
|
||||
// For glory.
|
||||
'X-Generator' => 'mPDF'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,606 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\CustomerRegisterRequest;
|
||||
use App\Http\Requests\LoginRequest;
|
||||
use App\Http\Requests\UpdateInfosRequest;
|
||||
use App\Mail\PasswordResetMail;
|
||||
use App\Mail\RegisterConfirmMail;
|
||||
use App\Models\Customers;
|
||||
use App\Models\Magasin;
|
||||
use App\Models\Order;
|
||||
use App\Models\PasswordReset;
|
||||
use App\Models\Salarie;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use LDC\LDCCRM\Enums\ApiError;
|
||||
use LDC\LDCCRM\Enums\Country;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\CrmException;
|
||||
use LDC\LDCCRM\Exceptions\ValidationException;
|
||||
use LDC\LDCCRM\Models\Customer as CrmCustomer;
|
||||
|
||||
class CustomerController extends Controller
|
||||
{
|
||||
/**
|
||||
* Affiche la page d'inscription
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function registerForm()
|
||||
{
|
||||
if (Auth::guard('customer')->check()) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
|
||||
return view('auth.register');
|
||||
}
|
||||
|
||||
/**
|
||||
* Enregistre le customer dans la base de données
|
||||
* et CRM
|
||||
*
|
||||
* @param CustomerRegisterRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function register(CustomerRegisterRequest $request)
|
||||
{
|
||||
try {
|
||||
return DB::transaction(function () use ($request) {
|
||||
$crmCustomer = new CrmCustomer(\array_intersect_key(
|
||||
$request->validated(),
|
||||
[
|
||||
'firstname' => '',
|
||||
'lastname' => '',
|
||||
'birth_date' => '',
|
||||
'address' => '',
|
||||
'postcode' => '',
|
||||
'country' => '',
|
||||
'city' => '',
|
||||
'phone' => '',
|
||||
'email' => '',
|
||||
'password' => '',
|
||||
'opt_in' => '',
|
||||
]
|
||||
));
|
||||
|
||||
$crmCustomer->city = $request->town;
|
||||
$crmCustomer->postcode = $request->postal_code;
|
||||
$crmCustomer->opt_in = $request->optin ? true : false;
|
||||
|
||||
// * Country Is forced to france
|
||||
$crmCustomer->country = Country::france();
|
||||
$crmCustomer->save();
|
||||
|
||||
// * Enrregistrement du Hashcode
|
||||
/** @var \App\Models\Customers $customer */
|
||||
$customer = new Customers($request->all());
|
||||
$customer->hashcode = $crmCustomer->hashcode;
|
||||
$customer->saveOrFail();
|
||||
|
||||
// * liaison éventuelle avec la table salaries
|
||||
if ($request->matricule && $request->code) {
|
||||
/** @var \App\Models\Salarie $salarie */
|
||||
$salarie = Salarie::where('matricule', '=', $request->matricule)
|
||||
->where('code', '=', $request->code)
|
||||
->firstOrFail();
|
||||
$salarie->customer()->associate($customer);
|
||||
$salarie->saveOrFail();
|
||||
}
|
||||
|
||||
Mail::to($request->email)->send(new RegisterConfirmMail($customer, $request->firstname));
|
||||
|
||||
return view('auth.register-success', ['mail' => $request->email]);
|
||||
});
|
||||
} catch (ApiErrorException $e) {
|
||||
if ($e->getApiError()->equals(ApiError::customerExists())) {
|
||||
return back()->withInput()->withErrors('Un compte est déjà associé à cette adresse email.');
|
||||
}
|
||||
if ($e->getApiError()->equals(ApiError::validationFailed())) {
|
||||
return back()->withInput()->withErrors($e->getMessage());
|
||||
}
|
||||
report($e);
|
||||
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return back()->withErrors("Salarié $request->matricule, $request->code introuvable.");
|
||||
} catch (ValidationException $e) {
|
||||
return back()->withErrors($e->getMessage());
|
||||
} catch (\Exception | \TypeError | CrmException $e) {
|
||||
report($e);
|
||||
// * Une erreur critique est survenue avec la CRM
|
||||
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
} //end try
|
||||
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la page de connexion
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function authenticateForm(Request $request)
|
||||
{
|
||||
if (Auth::guard('customer')->check()) {
|
||||
return redirect()->route('account.dashboard');
|
||||
}
|
||||
if ($request->get('url')) {
|
||||
Session::put('url.intended', $request->get('url'));
|
||||
Session::save();
|
||||
}
|
||||
return view('auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère l'authentification des customers
|
||||
*
|
||||
* @param LoginRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function authenticate(LoginRequest $request)
|
||||
{
|
||||
/** @var Customers|null */
|
||||
$customer = Customers::where('email', $request->email)->first();
|
||||
|
||||
try {
|
||||
/** @var \LDC\LDCCRM\CrmApiV2 */
|
||||
$crm = app('crmAPI');
|
||||
|
||||
// * Ne devrait pas survenir, $crm->login throws ApiError::authFailed()
|
||||
if (!$crm->login($request->email, $request->password)) {
|
||||
// * mauvais identifiants
|
||||
return back()->withErrors('Email ou mot de passe incorrect.');
|
||||
}
|
||||
|
||||
// Dans tout les cas : récupérer le crm user.
|
||||
$crmCustomer = $crm->getCustomer($request->email);
|
||||
|
||||
// Si pas de compte local mais existe en CRM.
|
||||
if (!$customer) {
|
||||
$customer = $this->createLocalCustomer($crmCustomer);
|
||||
}
|
||||
|
||||
return $this->processLogin($customer, $request->remember);
|
||||
} catch (ApiErrorException $e) {
|
||||
return $this->handleLoginApiErrorException($e, $request);
|
||||
} catch (CrmException | \Exception $e) {
|
||||
report($e);
|
||||
// Une erreur critique est survenue avec la CRM.
|
||||
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
} //end try
|
||||
}
|
||||
|
||||
/**
|
||||
* Active le compte d'un customer
|
||||
*
|
||||
* @param mixed $hashcode
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function activate($hashcode)
|
||||
{
|
||||
$hashcode = filter_var($hashcode, FILTER_SANITIZE_STRING);
|
||||
if (!($customer = Customers::select('hashcode')->where('hashcode', $hashcode)->first())) {
|
||||
return view('auth.activate')->with('message', 'Ce lien d\'activation n\'est pas valide.');
|
||||
}
|
||||
try {
|
||||
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
|
||||
$crmCustomer = $customer->apiData;
|
||||
if ($crmCustomer->activate()) {
|
||||
return view('auth.activate')
|
||||
->with('message', 'Votre compte a bien été activé, vous pouvez désormais vous connecter.');
|
||||
}
|
||||
} catch (ApiErrorException $e) {
|
||||
if ($e->getApiError()->equals(ApiError::customerAlreadyActive())) {
|
||||
// phpcs:disable Generic.Files.LineLength.TooLong
|
||||
return view('auth.activate')
|
||||
->with('message', 'Votre compte est déjà activé, vous pouvez dès à présent vous connecter avec celui-ci.');
|
||||
}
|
||||
report($e);
|
||||
// Une erreur critique est survenue avec la CRM.
|
||||
return view('auth.activate')
|
||||
->with('message', 'Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
} catch (CrmException $e) {
|
||||
report($e);
|
||||
// Une erreur critique est survenue avec la CRM.
|
||||
return view('auth.activate')
|
||||
->with('message', 'Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
} //end try
|
||||
return view('auth.activate')->with('message', 'Ce lien d\'activation n\'est pas valide.');
|
||||
}
|
||||
|
||||
/**
|
||||
* deconnexion customer
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
if (Auth::guard('customer')->check()) {
|
||||
Auth::guard('customer')->logout();
|
||||
return redirect()->route('home');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* page d'accès à la procédure mdp oublié
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function forgotPasswordForm(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
return view('auth.passwords.forgot');
|
||||
}
|
||||
|
||||
/**
|
||||
* initialisation de la procédure de mdp oublié
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function passwordReset(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email:rfc|max:255',
|
||||
]);
|
||||
|
||||
$email = filter_var($request->email, FILTER_SANITIZE_EMAIL);
|
||||
|
||||
$customerExist = Customers::where('email', $email)->count() === 0 ? false : true;
|
||||
|
||||
if ($customerExist) {
|
||||
// Suppression des anciens tokens.
|
||||
PasswordReset::where('email', $email)->delete();
|
||||
|
||||
$token = Str::random(80);
|
||||
|
||||
$passwordReset = new PasswordReset();
|
||||
$passwordReset->email = $email;
|
||||
$passwordReset->token = $token;
|
||||
$passwordReset->created_at = now();
|
||||
$passwordReset->save();
|
||||
|
||||
Mail::to($email)->send(new PasswordResetMail($token));
|
||||
return back()->with(
|
||||
'success',
|
||||
__("La procédure pour changer votre mot de passe a été envoyé sur votre email.")
|
||||
);
|
||||
} else {
|
||||
return back()->withErrors(__("Cette adresse email n'est pas enregistrée dans nos services."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the view used to change the password of a user when he required it
|
||||
* @param string $token Token used to identificate the user to change the password.
|
||||
* @return \Illuminate\Contracts\View\View The view to print
|
||||
*/
|
||||
public function viewChangePassword(string $token)
|
||||
{
|
||||
$pwdReset = PasswordReset::where('token', $token)->first();
|
||||
if (!$pwdReset) {
|
||||
abort(419);
|
||||
}
|
||||
$customer = Customers::where('email', $pwdReset->email)->first();
|
||||
if (!$customer) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return view('auth.passwords.reset', compact('customer'))->with('token', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* changement de mot de passe (depuis la procédure de mdp oublié)
|
||||
*
|
||||
* @param Request $request
|
||||
* @param mixed $token
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function changePassword(Request $request, $token)
|
||||
{
|
||||
$request->validate([
|
||||
'password' => 'required|confirmed|min:8|max:255'
|
||||
]);
|
||||
|
||||
/** @var \App\Models\PasswordReset $passwordReset */
|
||||
$passwordReset = PasswordReset::where('token', $token)->first();
|
||||
/** @var \App\Models\Customers $customer */
|
||||
$customer = Customers::where('email', optional($passwordReset)->email)->firstOrFail();
|
||||
|
||||
/** @var \LDC\LDCCRM\CrmApiV2 */
|
||||
$crm = app('crmAPI');
|
||||
|
||||
try {
|
||||
if ($crm->login($customer->email, $request->password)) {
|
||||
return back()->withErrors('Vous ne pouvez pas utiliser un de vos anciens mot de passe.');
|
||||
}
|
||||
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
} catch (ApiErrorException $e) {
|
||||
// * continue
|
||||
}
|
||||
|
||||
try {
|
||||
if (!($crmCustomer = $crm->getCustomer($customer->hashcode))) {
|
||||
return back()
|
||||
->withErrors('Changement impossible, compte inexistant.');
|
||||
}
|
||||
$crmCustomer->password = $request->password;
|
||||
$crmCustomer->save();
|
||||
} catch (\TypeError | CrmException | ApiErrorException $e) {
|
||||
report($e);
|
||||
// Une erreur critique est survenue avec la CRM.
|
||||
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
} catch (ValidationException $e) {
|
||||
return back()->withErrors(sprintf('Nouveau mot de passe : %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
$passwordReset->deleteOrFail();
|
||||
|
||||
return view('auth.passwords.reset-ok', compact('customer'));
|
||||
}
|
||||
|
||||
/**
|
||||
* profil client (mon compte)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function dashboard(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
// Show Profile.
|
||||
/** @var \App\Models\Customers|null $customer */
|
||||
$customer = Auth::guard('customer')->user();
|
||||
if (!$customer) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
|
||||
$crmCustomer = $customer->apiData;
|
||||
|
||||
/** @var object $crmInfos */
|
||||
$crmInfos = \json_decode(\json_encode($crmCustomer));
|
||||
$birthDate = explode('-', $crmCustomer->birth_date);
|
||||
|
||||
return view('customer.dashboard', compact('customer', 'crmInfos', 'birthDate'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a request to the CRM to change the given customer's informations
|
||||
* @param UpdateInfosRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function updateInfos(UpdateInfosRequest $request)
|
||||
{
|
||||
if (($result = $this->updateUserInfo($request)) === true) {
|
||||
return back()->with('success', trans(
|
||||
'Vos informations ont bien été enregistrées.'
|
||||
));
|
||||
}
|
||||
return back()->withInput()->withErrors(
|
||||
$result !== false ? $result : trans(
|
||||
'Une erreur est survenue, merci de réessayer ultérieurement.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* changement de mot de passe depuis le profil
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function changePasswordWhenAuthenticated(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'password' => 'required|min:8|confirmed|max:255'
|
||||
]);
|
||||
|
||||
$crm = app('crmApi');
|
||||
$customer = $crm->changePwdCustomer(Auth::guard('customer')->user()->crm_id, $request->password);
|
||||
|
||||
if ($customer->status === "OK") {
|
||||
return back()->with('success', __("Modifications enregistrés !"));
|
||||
} else {
|
||||
return back()->withErrors(__("Une erreur est survenue, merci de réessayer ultérieurement."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* affichage des commandes du customer connecté
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function myOrders(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
$orders = Order::where('customer_id', Auth::guard('customer')->user()->id)->orderBy('date', 'DESC')->get();
|
||||
return view('customer.my-orders', compact('orders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show detail commande
|
||||
*
|
||||
* @param string $reference
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function orderDetail(string $reference)
|
||||
{
|
||||
$order = Order::where('reference', '=', $reference)
|
||||
->where('customer_id', Auth::guard('customer')->user()->id)
|
||||
->firstOrFail();
|
||||
|
||||
if ($order->status_id == 1) {
|
||||
$magasin = null;
|
||||
} else {
|
||||
$magasin = Magasin::find($order->timeslot->magasin->id);
|
||||
}
|
||||
|
||||
return view('customer.order-detail', compact('order', 'magasin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* delete customers
|
||||
*
|
||||
* @param integer $id
|
||||
* @return void
|
||||
*/
|
||||
public function delete(int $id)
|
||||
{
|
||||
dump('deleting' . $id);
|
||||
die('Not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a local customer
|
||||
*
|
||||
* @param CrmCustomer $crmCustomer
|
||||
* @return \app\Models\Customers
|
||||
* @throws \Throwable If saving to DB failed.
|
||||
*/
|
||||
private function createLocalCustomer(CrmCustomer $crmCustomer): Customers
|
||||
{
|
||||
/** @var \App\Models\Customers $customer */
|
||||
$customer = Customers::firstOrNew([
|
||||
'email' => $crmCustomer->email
|
||||
]);
|
||||
$customer->hashcode = $crmCustomer->hashcode;
|
||||
$customer->saveOrFail();
|
||||
|
||||
return $customer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Api error exception
|
||||
*
|
||||
* @param ApiErrorException $e
|
||||
* @param LoginRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
private function handleLoginApiErrorException(ApiErrorException $e, LoginRequest $request)
|
||||
{
|
||||
/** @var Customers|null */
|
||||
$customer = Customers::where('email', $request->email)->first();
|
||||
/** @var \LDC\LDCCRM\CrmApiV2 */
|
||||
$crm = app('crmAPI');
|
||||
|
||||
switch ($e->getApiError()) {
|
||||
case ApiError::authFailed():
|
||||
// * mauvais identifiants
|
||||
return back()->withErrors('Email ou mot de passe incorrect.');
|
||||
case ApiError::customerNotActivated():
|
||||
// * le compte n'est pas activé
|
||||
if (!$customer) {
|
||||
try {
|
||||
if (!($crmCustomer = $crm->getCustomer($request->email))) {
|
||||
Log::critical(sprintf('Customer %s coulnd not be retrieved from crm', $request->email));
|
||||
return back()->withErrors(
|
||||
trans('Une erreur est survenue, merci de réessayer ultérieurement.')
|
||||
);
|
||||
}
|
||||
$customer = $this->createLocalCustomer($crmCustomer);
|
||||
} catch (CrmException | ApiErrorException $e) {
|
||||
report($e);
|
||||
// Une erreur critique est survenue avec la CRM.
|
||||
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
}
|
||||
}
|
||||
Mail::to($request->email)->send(new RegisterConfirmMail($customer, null));
|
||||
return back()
|
||||
->withErrors(
|
||||
trans('Votre compte n\'est pas activé, vérifiez dans vos emails pour y trouver
|
||||
le mail de confirmation. Un lien d\'activation vous a été renvoyé.')
|
||||
);
|
||||
default:
|
||||
report($e);
|
||||
// * une erreur non gérée
|
||||
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
|
||||
} //end switch
|
||||
}
|
||||
|
||||
/**
|
||||
* Login a customer
|
||||
*
|
||||
* @param Customers $customer
|
||||
* @param boolean $remember
|
||||
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
private function processLogin(Customers $customer, bool $remember)
|
||||
{
|
||||
/** @var \Illuminate\Auth\SessionGuard */
|
||||
$guard = auth('customer');
|
||||
$guard->login($customer, $remember);
|
||||
$url = Session::pull('url.intended');
|
||||
Session::forget('url.intended');
|
||||
Session::save();
|
||||
return !empty($url) ? redirect()->to($url) : redirect()->route('account.dashboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates user info
|
||||
*
|
||||
* @param UpdateInfosRequest $request
|
||||
* @return boolean|string return strictly true if success,
|
||||
* false il failed, could be a string with message error if failed
|
||||
*/
|
||||
private function updateUserInfo(UpdateInfosRequest $request)
|
||||
{
|
||||
/** @var \App\Models\Customers */
|
||||
$customer = auth('customer')->user();
|
||||
if (!$customer) {
|
||||
return \redirect()->back();
|
||||
}
|
||||
|
||||
/** @var \LDC\LDCCRM\Models\Customer */
|
||||
$crmCustomer = $customer->apiData;
|
||||
|
||||
$data = [
|
||||
'firstname' => $request->firstname,
|
||||
'lastname' => $request->lastname,
|
||||
'birth_date' => $request->year . '-' . $request->month . '-' . $request->day,
|
||||
'address' => $request->address,
|
||||
'postcode' => $request->postcode,
|
||||
'city' => $request->city,
|
||||
'phone' => \strval($request->phone),
|
||||
'opt_in' => \boolval($request->optin),
|
||||
];
|
||||
|
||||
// * remove phone if empty
|
||||
if (isset($data['phone']) and !strlen($data['phone'])) {
|
||||
unset($data['phone']);
|
||||
}
|
||||
|
||||
try {
|
||||
$crmCustomer->fill($data);
|
||||
$crmCustomer->save();
|
||||
} catch (ValidationException $e) {
|
||||
return $e->getMessage();
|
||||
} catch (ApiErrorException $e) {
|
||||
if ($e->getApiError()->equals(ApiError::validationFailed())) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
report($e);
|
||||
return false;
|
||||
} catch (CrmException | \TypeError $e) {
|
||||
report($e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
35
app/Http/Controllers/Fo/Auth/ConfirmPasswordController.php
Normal file
35
app/Http/Controllers/Fo/Auth/ConfirmPasswordController.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\ConfirmsPasswords;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ConfirmPasswordController extends Controller
|
||||
{
|
||||
use ConfirmsPasswords;
|
||||
|
||||
/**
|
||||
* Display the password confirmation view.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showConfirmForm()
|
||||
{
|
||||
if (Auth::guard('frontend')->check()) {
|
||||
return \response()->redirectToRoute('home');
|
||||
}
|
||||
return view('theme::auth.passwords.confirm');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post register / login redirect path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function redirectPath()
|
||||
{
|
||||
return response()->redirectToRoute('account.dashboard')->getTargetUrl();
|
||||
}
|
||||
}
|
||||
82
app/Http/Controllers/Fo/Auth/ForgotPasswordController.php
Normal file
82
app/Http/Controllers/Fo/Auth/ForgotPasswordController.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
use SendsPasswordResetEmails;
|
||||
|
||||
/**
|
||||
* Message to user
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $message =
|
||||
'Si votre compte existe vous devriez recevoir un message avec un lien pour réinitialiser votre mot de passe';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest:frontend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the form to request a password reset link.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showLinkRequestForm()
|
||||
{
|
||||
return view('theme::auth.passwords.email');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the broker to be used during password reset.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\PasswordBroker
|
||||
*/
|
||||
public function broker()
|
||||
{
|
||||
return Password::broker('customers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a successful password reset link.
|
||||
* ! Dans les deux cas on ne divulgue pas si un user existe.
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function sendResetLinkResponse()
|
||||
{
|
||||
return back()->with('info', trans($this->message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a failed password reset link.
|
||||
* ! Dans les deux cas on ne divulgue pas si un user existe.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function sendResetLinkFailedResponse(Request $request, string $response)
|
||||
{
|
||||
// ! Ne pas notifier que l'utilisateur n'existe pas.
|
||||
if ($response === 'passwords.user') {
|
||||
return back()->with('info', trans($this->message));
|
||||
}
|
||||
// * Renvoyer les autres message d'erreur style throttle.
|
||||
return back()
|
||||
->withInput($request->only('email'))
|
||||
->withErrors(['email' => trans($response)]);
|
||||
}
|
||||
}
|
||||
92
app/Http/Controllers/Fo/Auth/LoginController.php
Normal file
92
app/Http/Controllers/Fo/Auth/LoginController.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Foundation\Auth\ThrottlesLogins;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
use AuthenticatesUsers;
|
||||
use ThrottlesLogins;
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = RouteServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest:frontend')->except('logout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the guard to be used during authentication.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
{
|
||||
return Auth::guard('frontend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application's login form.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showLoginForm()
|
||||
{
|
||||
return view('theme::auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* The user has been authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Database\Eloquent\Model $user
|
||||
* @return mixed
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing, Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
*/
|
||||
protected function authenticated(Request $request, Model $user)
|
||||
{
|
||||
$user->last_connection = \now();
|
||||
$user->saveOrFail();
|
||||
Session::flash('info', trans('Vous êtes à présent connecté'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The user has logged out of the application.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
protected function loggedOut(Request $request)
|
||||
{
|
||||
Session::flash('info', trans('Vous êtes à présent déconnecté'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post register / login redirect path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function redirectPath()
|
||||
{
|
||||
return response()->redirectToIntended()->getTargetUrl();
|
||||
}
|
||||
}
|
||||
184
app/Http/Controllers/Fo/Auth/RegisterController.php
Normal file
184
app/Http/Controllers/Fo/Auth/RegisterController.php
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\Customers\CreateAccountRequest;
|
||||
use App\Models\Customer\Customer;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use LDC\LDCCRM\Enums\ApiError;
|
||||
use LDC\LDCCRM\Enums\Country;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\ValidationException as ExceptionsValidationException;
|
||||
use LDC\LDCCRM\Models\Customer as CrmCustomer;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
use RegistersUsers;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest:frontend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the guard to be used during authentication.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
{
|
||||
return Auth::guard('frontend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application registration form.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showRegistrationForm()
|
||||
{
|
||||
return view('theme::auth.register');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
* @throws \Illuminate\Validation\ValidationException If data is incorrect.
|
||||
*/
|
||||
protected function validator(array $data)
|
||||
{
|
||||
$data['ok_cgv'] = \request()->boolean('ok_cgv');
|
||||
$data['phone'] = $data['phone'] ?? null;
|
||||
$data['opt_in'] = ($data['opt_in'] ?? false) ? true : false;
|
||||
|
||||
$request = new CreateAccountRequest();
|
||||
|
||||
$validateData = Validator::make(
|
||||
$data,
|
||||
$request->rules(),
|
||||
$request->messages(),
|
||||
$request->attributes()
|
||||
);
|
||||
|
||||
if ($validateData) {
|
||||
return $validateData;
|
||||
} else {
|
||||
try {
|
||||
(new CrmCustomer())->fill($this->getOnlyCrmData($data));
|
||||
} catch (ExceptionsValidationException $e) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \App\Models\Customer
|
||||
* @throws \Illuminate\Validation\ValidationException If there are validation errors.
|
||||
* @throws \RuntimeException On unhandled api Error.
|
||||
*/
|
||||
protected function create(array $data)
|
||||
{
|
||||
$data['country'] = Country::france();
|
||||
$data['ok_cgv'] = \request()->boolean('ok_cgv');
|
||||
$data['phone'] = $data['phone'] ?? null;
|
||||
$data['opt_in'] = ($data['opt_in'] ?? false) ? true : false;
|
||||
|
||||
try {
|
||||
return DB::transaction(function () use ($data) {
|
||||
$crmCustomer = new CrmCustomer($this->getOnlyCrmData($data));
|
||||
|
||||
// * Country Is forced to france
|
||||
$crmCustomer->country = Country::france();
|
||||
$crmCustomer->save();
|
||||
|
||||
// * Enregistrement du Hashcode
|
||||
/** @var \App\Models\Customer\Customer $customer */
|
||||
$customer = new Customer($data);
|
||||
$customer->hashcode = $crmCustomer->hashcode;
|
||||
// * Customer will be logged in.
|
||||
$customer->last_connection = \now();
|
||||
$customer->saveOrFail();
|
||||
|
||||
if ($customer->saveOrFail()) {
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
Session::flash('success', trans('Votre compte à bien été crée, vous devez valider votre adresse email, un email de confirmation vous à été envoyé.'));
|
||||
}
|
||||
|
||||
return $customer;
|
||||
});
|
||||
} catch (ApiErrorException $e) {
|
||||
if ($e->getApiError()->equals(ApiError::customerExists())) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => 'Un compte est déjà associé à cette adresse email.'
|
||||
]);
|
||||
}
|
||||
if ($e->getApiError()->equals(ApiError::validationFailed())) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
report($e);
|
||||
Log::error(__CLASS__ . '::create reached end of possibilities.');
|
||||
throw new \RuntimeException(__CLASS__ . '::create reached end of possibilities.');
|
||||
} catch (ExceptionsValidationException $e) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
} //end try
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post register / login redirect path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function redirectPath()
|
||||
{
|
||||
return response()->redirectToRoute('account.dashboard')->getTargetUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only data used in crm
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
private function getOnlyCrmData(array $data): array
|
||||
{
|
||||
return \array_intersect_key(
|
||||
$data,
|
||||
[
|
||||
'firstname' => '',
|
||||
'lastname' => '',
|
||||
'birth_date' => '',
|
||||
'address' => '',
|
||||
'postcode' => '',
|
||||
'country' => '',
|
||||
'city' => '',
|
||||
'phone' => '',
|
||||
'email' => '',
|
||||
'password' => '',
|
||||
'opt_in' => '',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
121
app/Http/Controllers/Fo/Auth/ResetPasswordController.php
Normal file
121
app/Http/Controllers/Fo/Auth/ResetPasswordController.php
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\CrmException;
|
||||
use LDC\LDCCRM\Exceptions\ValidationException as ExceptionsValidationException;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest:frontend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the guard to be used during authentication.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
{
|
||||
return Auth::guard('frontend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the password reset view for the given token.
|
||||
*
|
||||
* If no token is present, display the link request form.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function showResetForm(Request $request)
|
||||
{
|
||||
$token = $request->route()->parameter('token');
|
||||
|
||||
return view('theme::auth.passwords.reset')->with(
|
||||
['token' => $token, 'email' => $request->email]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the given user's password.
|
||||
*
|
||||
* @param mixed $customer
|
||||
* @param mixed $password
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException If something goes wrong.
|
||||
*/
|
||||
protected function resetPassword($customer, $password)
|
||||
{
|
||||
/** @var \App\Models\Customer\Customer $user */
|
||||
/** @var string $password */
|
||||
|
||||
/** @var \LDC\LDCCRM\CrmApiV2 */
|
||||
$crm = app('crmAPI');
|
||||
|
||||
try {
|
||||
if (!($crmCustomer = $crm->getCustomer($customer->hashcode))) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => 'Changement impossible, compte inexistant.'
|
||||
]);
|
||||
}
|
||||
$crmCustomer->password = $password;
|
||||
$crmCustomer->save();
|
||||
} catch (\TypeError | CrmException | ApiErrorException $e) {
|
||||
report($e);
|
||||
throw ValidationException::withMessages([
|
||||
'error' => 'Une erreur est survenue, merci de réessayer ultérieurement.'
|
||||
]);
|
||||
} catch (ExceptionsValidationException $e) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
$customer->setRememberToken(Str::random(60));
|
||||
|
||||
$customer->save();
|
||||
|
||||
event(new PasswordReset($customer));
|
||||
|
||||
$this->guard()->login($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post register / login redirect path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function redirectPath()
|
||||
{
|
||||
return response()->redirectToRoute('account.dashboard')->getTargetUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the broker to be used during password reset.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\PasswordBroker
|
||||
*/
|
||||
public function broker()
|
||||
{
|
||||
return Password::broker('customers');
|
||||
}
|
||||
}
|
||||
47
app/Http/Controllers/Fo/Auth/VerificationController.php
Normal file
47
app/Http/Controllers/Fo/Auth/VerificationController.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\VerifiesEmails;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class VerificationController extends Controller
|
||||
{
|
||||
use VerifiesEmails;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:frontend');
|
||||
$this->middleware('signed:relative')->only('verify');
|
||||
$this->middleware('throttle:6,1')->only('verify', 'resend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the email verification notice.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
public function show(Request $request)
|
||||
{
|
||||
return $request->user()->hasVerifiedEmail()
|
||||
? redirect($this->redirectPath())
|
||||
: view('theme::auth.verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post register / login redirect path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function redirectPath()
|
||||
{
|
||||
return response()->redirectToRoute('account.dashboard')->getTargetUrl();
|
||||
}
|
||||
}
|
||||
165
app/Http/Controllers/Fo/BasketController.php
Normal file
165
app/Http/Controllers/Fo/BasketController.php
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Enums\Product\WeightUnit;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Models\Merchandise\Product;
|
||||
use Gloudemans\Shoppingcart\CartItem;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class BasketController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get Basket
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getBasket()
|
||||
{
|
||||
$this->authorize('useBasketSystem', Product::class);
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
return \response()->json(ToolboxHelper::cartToList($basket));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajout d'un produit au panier
|
||||
*
|
||||
* ! Assert Model found, status true and orderable true.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws \Illuminate\Validation\ValidationException Si le produit n'est pas disponible (orderable).
|
||||
*/
|
||||
public function addToBasket(Product $product)
|
||||
{
|
||||
$this->authorize('useBasketSystem', Product::class);
|
||||
$this->authorize('addToCart', $product);
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
$basket = $this->filterBasketKeepOnlyOrderableItems($basket);
|
||||
|
||||
if (!$product->status or !$product->orderable) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => \trans('Ce produit n\'est plus disponible')
|
||||
]);
|
||||
}
|
||||
|
||||
$cartItemOptions = \array_merge(static::$cartItemOptionsSkel, [
|
||||
'reference' => $product->reference,
|
||||
'slug' => $product->slug,
|
||||
'picture' => $product->picture,
|
||||
'sell_unit' => $product->sell_unit,
|
||||
'weight_with_unit' => WeightUnit::getDisplayableWeight($product->weight),
|
||||
// * Prix ttc du produit
|
||||
'price_ttc' => $product->price_ttc,
|
||||
// * Prix ttc du produit remisé
|
||||
'undiscounted_price_ttc' => $product->undiscounted_price_ttc,
|
||||
'tax_rate' => $product->tax_rate->rate,
|
||||
'discount_type' => \optional(\optional($product->discount)->type)->value,
|
||||
'discount_rate' => $product->discount_rate,
|
||||
]);
|
||||
|
||||
$cartItem = CartItem::fromBuyable($product, $cartItemOptions);
|
||||
$cartItem->setQuantity(1);
|
||||
$cartItem->associate($product);
|
||||
// * Validate Cart Item.
|
||||
$jsonCartObject = \json_decode($cartItem->toJson());
|
||||
if (!ToolboxHelper::basketObjectIsValid($jsonCartObject)) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => \trans('Cart item is not valid')
|
||||
]);
|
||||
}
|
||||
$basket->addCartItem($cartItem);
|
||||
|
||||
// ! https://github.com/bumbummen99/LaravelShoppingcart/pull/181
|
||||
// * Note Lib is is actually refactoring for laravel 9 php8 only
|
||||
// * https://github.com/bumbummen99/LaravelShoppingcart/pull/145
|
||||
// ! These lines are required to prevent amount bug (after adding to basket).
|
||||
// ! This because of the cart calculator I guess.
|
||||
$cartItem->setTaxRate($product->tax_rate->rate / 100);
|
||||
$cartItem->setDiscountRate($product->discount_rate);
|
||||
|
||||
return \response()->json(ToolboxHelper::cartToList($basket));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrait d'un produit du panier (1 quantité d'1 type)
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function removeFromBasket(Product $product)
|
||||
{
|
||||
$this->authorize('useBasketSystem', Product::class);
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\CartItem|null */
|
||||
$basketItem = $basket->content()->where('id', $product->id)->first();
|
||||
|
||||
/** @var string|null */
|
||||
$rowId = \optional($basketItem)->rowId;
|
||||
/** @var integer|null */
|
||||
$qty = \optional($basketItem)->qty;
|
||||
|
||||
if ($rowId and !\is_null($qty)) {
|
||||
$basket->update($rowId, $qty - 1);
|
||||
}
|
||||
|
||||
$basket = $this->filterBasketKeepOnlyOrderableItems($basket);
|
||||
|
||||
return \response()->json(ToolboxHelper::cartToList($basket));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrait d'un type produit du panier (toute les quantités d'1 type)
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function removeItemTypeFromBasket(Product $product)
|
||||
{
|
||||
$this->authorize('useBasketSystem', Product::class);
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\CartItem|null */
|
||||
$basketItem = $basket->content()->where('id', $product->id)->first();
|
||||
|
||||
/** @var string|null */
|
||||
$rowId = \optional($basketItem)->rowId;
|
||||
|
||||
if ($rowId) {
|
||||
$basket->remove($rowId);
|
||||
}
|
||||
|
||||
$basket = $this->filterBasketKeepOnlyOrderableItems($basket);
|
||||
|
||||
return \response()->json(ToolboxHelper::cartToList($basket));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrait d'un type produit du panier (toute les quantités d'1 type)
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function emptyBasket()
|
||||
{
|
||||
$this->authorize('useBasketSystem', Product::class);
|
||||
|
||||
OrderController::destroyCurrentBasket();
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
return \response()->json(ToolboxHelper::cartToList($basket));
|
||||
}
|
||||
}
|
||||
49
app/Http/Controllers/Fo/ContactController.php
Normal file
49
app/Http/Controllers/Fo/ContactController.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Enums\StaticPageType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\ContactFormRequest;
|
||||
use App\Models\Customer\Contact;
|
||||
use App\Models\Shop\Shop;
|
||||
use App\Models\Site\StaticPage;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display contact from
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function contact()
|
||||
{
|
||||
$content = StaticPage::getPageOfType(StaticPageType::contact());
|
||||
|
||||
$firstShop = Shop::firstOrFail();
|
||||
|
||||
return view('theme::pages.contact', compact('content', 'firstShop'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit contact form
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\ContactFormRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function contactSubmit(ContactFormRequest $request)
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$contact = new Contact();
|
||||
$contact->fill($request->validated());
|
||||
|
||||
if ($contact->saveOrFail()) {
|
||||
return redirect()->back()
|
||||
->with('success', trans('Votre message à été envoyé'));
|
||||
}
|
||||
return redirect()->back()
|
||||
->with('error', trans('Votre message n\'a pas pu être envoyé'));
|
||||
});
|
||||
}
|
||||
}
|
||||
267
app/Http/Controllers/Fo/CustomerController.php
Normal file
267
app/Http/Controllers/Fo/CustomerController.php
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\Ajax\SubscribeNewsletterRequest;
|
||||
use App\Http\Requests\Fo\Customers\ConfirmDeleteRequest;
|
||||
use App\Http\Requests\Fo\Customers\UpdateEmailRequest;
|
||||
use App\Http\Requests\Fo\Customers\UpdatePasswordRequest;
|
||||
use App\Http\Requests\Fo\Customers\UpdateInfosRequest;
|
||||
use App\Models\Customer\Customer;
|
||||
use App\Models\Shop\Order;
|
||||
use App\Notifications\Customer\UpdateEmail as NotificationUpdateEmail;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use LDC\LDCCRM\Enums\ApiError;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\CrmException;
|
||||
use LDC\LDCCRM\Exceptions\ValidationException as CrmValidationException;
|
||||
use LDC\LDCCRM\Models\SingleOptin;
|
||||
|
||||
class CustomerController extends Controller
|
||||
{
|
||||
// * --- Backoffice ---
|
||||
|
||||
/**
|
||||
* profil client (mon compte)
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function dashboard()
|
||||
{
|
||||
// Show Profile.
|
||||
/** @var \App\Models\Customer|null $customer */
|
||||
$customer = Auth::guard('frontend')->user();
|
||||
if (!$customer) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
|
||||
$crmCustomer = $customer->apiData;
|
||||
|
||||
/** @var object $crmInfos */
|
||||
$crmInfos = \json_decode(\json_encode($crmCustomer));
|
||||
|
||||
return view('theme::pages.customer.dashboard', compact('customer', 'crmInfos'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show update customer informations form
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function email()
|
||||
{
|
||||
return view('theme::auth.change-email');
|
||||
}
|
||||
|
||||
/**
|
||||
* Uupdate customer email
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Customers\UpdateEmailRequest $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function emailSubmit(UpdateEmailRequest $request)
|
||||
{
|
||||
/** @var \App\Models\Customer\Customer */
|
||||
$customer = \auth('frontend')->user();
|
||||
$customer->notify(new NotificationUpdateEmail());
|
||||
|
||||
return $this->updateCrmCustomerInfo($customer, ['email' => $request->get('email')]) ?
|
||||
back()->with('success', trans('Vos informations ont bien été enregistrées.')) :
|
||||
back()->withInput()->withErrors(trans('Une erreur est survenue, merci de réessayer ultérieurement.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show update customer password form
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function password()
|
||||
{
|
||||
return view('theme::auth.passwords.change');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update customer password
|
||||
*
|
||||
* @param UpdatePasswordRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function passwordSubmit(UpdatePasswordRequest $request)
|
||||
{
|
||||
/** @var \App\Models\Customer\Customer */
|
||||
$customer = \auth('frontend')->user();
|
||||
|
||||
if ($this->updateCrmCustomerInfo($customer, ['password' => $request->get('password')])) {
|
||||
event(new PasswordReset($customer));
|
||||
return back()->with('success', trans('Vos informations ont bien été enregistrées.'));
|
||||
}
|
||||
|
||||
return back()->withInput()->withErrors(trans('Une erreur est survenue, merci de réessayer ultérieurement.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to the CRM to change the given customer's informations
|
||||
* @param \App\Http\Requests\Fo\UpdateInfosRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function updateInfos(UpdateInfosRequest $request)
|
||||
{
|
||||
/** @var \App\Models\Customer\Customer */
|
||||
$customer = auth('frontend')->user();
|
||||
|
||||
return $this->updateCrmCustomerInfo($customer, $request->validated()) ?
|
||||
back()->with('success', trans('Vos informations ont bien été enregistrées.')) :
|
||||
back()->withInput()->withErrors(trans('Une erreur est survenue, merci de réessayer ultérieurement.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show customer delete account page
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
return view('theme::pages.customer.destroy');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show customer delete account page
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Customers\ConfirmDeleteRequest $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function destroySubmit(ConfirmDeleteRequest $request)
|
||||
{
|
||||
if ($request->confirm) {
|
||||
try {
|
||||
return DB::transaction(function () {
|
||||
/** @var \App\Models\Customer\Customer */
|
||||
$customer = auth('frontend')->user();
|
||||
$customer->deleteOrFail();
|
||||
|
||||
// * Force logout
|
||||
auth('frontend')->logout();
|
||||
|
||||
return response()
|
||||
->redirectToRoute('home')
|
||||
->with('info', trans(
|
||||
'Votre compte à bien été marqué pour suppression,
|
||||
vous pourrez le réactiver en vous reconnectant à celui-ci avant
|
||||
qu\'il ne soit définitivement supprimé au bout d\'une semaine.'
|
||||
));
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
Session::flash('error', trans('Une erreur est survenue veuillez réssayer plus tard.'));
|
||||
} //end try
|
||||
} //end if
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates user info
|
||||
*
|
||||
* @param \App\Models\Customer\Customer $customer
|
||||
* @param array $data
|
||||
* @return boolean
|
||||
* @throws \Illuminate\Validation\ValidationException If something failed.
|
||||
*/
|
||||
private function updateCrmCustomerInfo(Customer $customer, array $data)
|
||||
{
|
||||
return DB::transaction(function () use ($customer, $data) {
|
||||
try {
|
||||
/** @var \LDC\LDCCRM\Models\Customer */
|
||||
$crmCustomer = $customer->apiData;
|
||||
if (\array_key_exists('email', $data)) {
|
||||
$customer->email = $data['email'];
|
||||
$customer->saveOrFail();
|
||||
}
|
||||
$crmCustomer->fill($data);
|
||||
$saved = $crmCustomer->save();
|
||||
// * Sync with stripe if already known by stripe.
|
||||
if ($customer->stripe_id) {
|
||||
$customer->syncStripeCustomerDetails();
|
||||
}
|
||||
return $saved;
|
||||
} catch (CrmValidationException $e) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
} catch (ApiErrorException $e) {
|
||||
if ($e->getApiError()->equals(ApiError::validationFailed())) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
report($e);
|
||||
return false;
|
||||
} //end try
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Affichage des commandes du customer connecté
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function myOrders()
|
||||
{
|
||||
/** @var \App\Models\Customer\Customer */
|
||||
$customer = auth('frontend')->user();
|
||||
|
||||
$orders = $customer->orders()->orderBy('created_at', 'DESC')->paginate();
|
||||
return view('theme::pages.customer.orders', compact('orders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show detail commande
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function orderDetail(Order $order)
|
||||
{
|
||||
$order->load([
|
||||
'timeslot.shop',
|
||||
'transactions.order.customer'
|
||||
]);
|
||||
return view('theme::pages.customer.orders.show', compact('order'));
|
||||
}
|
||||
|
||||
// * --- END Backoffice ---
|
||||
|
||||
/**
|
||||
* Call the CRM to add a single optin
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Ajax\SubscribeNewsletterRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
*/
|
||||
public function addOptIn(SubscribeNewsletterRequest $request)
|
||||
{
|
||||
try {
|
||||
SingleOptin::setStatus($request->email, true);
|
||||
return \response()->json();
|
||||
} catch (ApiErrorException $e) {
|
||||
// * Il y a deja un customerInfo avec optin a true pour ce customer
|
||||
if ($e->getApiError()->equals(ApiError::singleOptinCustomerExists())) {
|
||||
return \response()->json([
|
||||
'errors' => [
|
||||
'email' => [\trans('Vous êtes déjà inscrit avec cette adresse email')]
|
||||
]
|
||||
], 422);
|
||||
}
|
||||
report($e);
|
||||
return \response()->json([], 500);
|
||||
} catch (CrmException $e) {
|
||||
report($e);
|
||||
return \response()->json([], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
926
app/Http/Controllers/Fo/OrderController.php
Normal file
926
app/Http/Controllers/Fo/OrderController.php
Normal file
|
|
@ -0,0 +1,926 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Enums\Order\DeliveryModeEnum;
|
||||
use App\Enums\Order\DeliveryStatus;
|
||||
use App\Enums\Order\OrderProcess;
|
||||
use App\Enums\Order\PaymentModeEnum;
|
||||
use App\Enums\Order\PaymentStatus;
|
||||
use App\Enums\Order\TransactionStatus;
|
||||
use App\Enums\Order\TransactionType;
|
||||
use App\Enums\Order\ValidationStatus;
|
||||
use App\Events\OrderIsCreated;
|
||||
use App\Events\OrderIsPaid;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\Orders\CheckoutRequest;
|
||||
use App\Http\Requests\Fo\Orders\SetOrderTimeSlotRequest;
|
||||
use App\Http\Requests\Fo\Orders\ShippingFormRequest;
|
||||
use App\Http\Requests\Fo\Orders\ShippingModeFormRequest;
|
||||
use App\Http\Resources\ShopResource;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Models\Customer\Customer;
|
||||
use App\Models\Payment\Transaction;
|
||||
use App\Models\Shop\DeliveryMode;
|
||||
use App\Models\Shop\Order;
|
||||
use App\Models\Shop\Shop;
|
||||
use App\Models\Shop\Timeslot;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use LDC\LDCCRM\Enums\Country;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
/**
|
||||
* OrderController
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(function (Request $request, callable $next) {
|
||||
// * On peut passer commande ?
|
||||
$this->authorize('orderThings', Order::class);
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
// * --- TUNNEL DE COMMANDE ---
|
||||
/**
|
||||
* Récapitualtif du panier
|
||||
*
|
||||
* * --- 1 ---
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function basketRecap()
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertBasketHasMinAmount();
|
||||
$this->setOrderProcessStep(OrderProcess::reviewBasket());
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
$messages = [];
|
||||
|
||||
$basket = $this->filterBasketKeepOnlyOrderableItems($basket, $messages);
|
||||
|
||||
if (!empty($messages)) {
|
||||
Session::flash('warning', \collect($messages)->implode(",\n"));
|
||||
}
|
||||
|
||||
$basketItems = ToolboxHelper::cartToList($basket);
|
||||
|
||||
return view('theme::pages.order-tunnel.basket-recap', compact(
|
||||
'basket',
|
||||
'basketItems'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select shipping Mode And create Session Order
|
||||
*
|
||||
* * --- 2 ---
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function shippingMode()
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertBasketHasMinAmount();
|
||||
$this->setOrderProcessStep(OrderProcess::shippingMethod(), OrderProcess::reviewBasket());
|
||||
|
||||
// * CREATE ORDER
|
||||
|
||||
/** @var \App\Models\Customer\Customer $customer */
|
||||
$customer = auth('frontend')->user();
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
/** @var \App\Models\Shop\Order|null $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
|
||||
// * If there was a previous order that was not ended use the ID.
|
||||
/** @var \App\Models\Shop\Order */
|
||||
$order = $order ?? new Order();
|
||||
$order->mail_sent = false;
|
||||
$order->delivery_status = DeliveryStatus::pending();
|
||||
$order->payment_status = PaymentStatus::pending();
|
||||
$order->validation_status = ValidationStatus::pending();
|
||||
$order->assignBasket($basket);
|
||||
$order->customer()->associate($customer);
|
||||
|
||||
// * Save Session Order
|
||||
Session::put('currentOrder', $order);
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Shop\DeliveryMode> */
|
||||
$deliveryModes = app('DeliveryModesGlobal');
|
||||
|
||||
return \view('theme::pages.order-tunnel.shipping-mode', \compact('deliveryModes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save shipping Mode
|
||||
*
|
||||
* * --- 2 ---
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Orders\ShippingModeFormRequest $request
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function shippingModeSubmit(ShippingModeFormRequest $request)
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertBasketHasMinAmount();
|
||||
$this->assertDoesHaveCurrentOrder();
|
||||
$this->setOrderProcessStep(OrderProcess::shippingMethod(), OrderProcess::reviewBasket());
|
||||
|
||||
/** @var \App\Models\Shop\DeliveryMode $mode */
|
||||
if (!($mode = DeliveryMode::availables()->where('mode', $request->mode)->first())) {
|
||||
$e = new \RuntimeException('Mode de livraison non disponible', 1);
|
||||
report($e);
|
||||
Session::flash('error', trans('Mode de livraison non disponible'));
|
||||
return \back()->withException($e);
|
||||
}
|
||||
|
||||
self::allowTimeSlotSelect();
|
||||
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
|
||||
$order->deliveryMode()->associate($mode);
|
||||
|
||||
Session::put('currentOrder', $order);
|
||||
|
||||
return \response()->redirectToRoute('order-tunnel.shipping');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shipping informations
|
||||
*
|
||||
* * --- 3 ---
|
||||
*
|
||||
* ! Pour - Click and collect
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
* @throws \RuntimeException If delivery mode is unhandled.
|
||||
*/
|
||||
public function shipping()
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertBasketHasMinAmount();
|
||||
$this->assertDoesHaveCurrentOrder();
|
||||
$this->assertDeliveryModeIsValid();
|
||||
$this->setOrderProcessStep(OrderProcess::shippment(), OrderProcess::shippingMethod());
|
||||
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
|
||||
// * Switch Delivery modes
|
||||
// * Pour afficher formulaire qui devra retourner une adresse 'shipping'
|
||||
/**
|
||||
* * Switch Delivery modes
|
||||
* - Pour afficher formulaire qui devra retourner une adresse 'shipping'.
|
||||
* - Qui devra fournir un timeslot dans le cas de clickAndCollect.
|
||||
*/
|
||||
/** @var \App\Enums\Order\DeliveryModeEnum|null */
|
||||
$delivery_mode = \optional($order->deliveryMode)->mode;
|
||||
switch ($delivery_mode) {
|
||||
case DeliveryModeEnum::inShop():
|
||||
// * 1 Select timeslot if not already done.
|
||||
if (!$order->timeslot()->first() or !self::allowedTimeSlotSelect()) {
|
||||
$shops = Shop::all()->map(function (Shop $shop) {
|
||||
return new ShopResource($shop);
|
||||
});
|
||||
/** @var \App\Models\Shop\Timeslot|null */
|
||||
$timeslot = $order->timeslot;
|
||||
/** @var \App\Models\Shop\Shop|null */
|
||||
$shop = $timeslot ? $timeslot->shop : null;
|
||||
View::share('deliveryModePickSlot', Session::get('deliveryModePickSlot'));
|
||||
return \view('theme::pages.order-tunnel.pick-slot', \compact(
|
||||
'order',
|
||||
'shops',
|
||||
'timeslot',
|
||||
'shop'
|
||||
));
|
||||
}
|
||||
/** @var \App\Models\Customer\Customer */
|
||||
$customer = auth('frontend')->user();
|
||||
return \view('theme::pages.order-tunnel.shipping', [
|
||||
'order' => $order, 'customer_info' => $customer->api_data
|
||||
]);
|
||||
default:
|
||||
throw new \RuntimeException('Unhandled delivery mode ');
|
||||
}//end switch
|
||||
|
||||
throw new \RuntimeException('This should never happen');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save and validate timeslot
|
||||
*
|
||||
* * --- 3 ---
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Orders\SetOrderTimeSlotRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Validation\ValidationException If Creneau is not available anomore.
|
||||
*/
|
||||
public function validateSelectedTimeSlot(SetOrderTimeSlotRequest $request)
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertBasketHasMinAmount();
|
||||
$this->assertDoesHaveCurrentOrder();
|
||||
$this->setOrderProcessStep(OrderProcess::shippment(), OrderProcess::shippingMethod());
|
||||
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
|
||||
/** @var \App\Models\Shop\Timeslot|null $timeslot */
|
||||
$timeslot = $order->timeslot;
|
||||
|
||||
/** @var \App\Models\Shop\Shop */
|
||||
$shop = Shop::query()->where('id', $request->shop_id)->firstOrFail();
|
||||
$creneau = Carbon::createFromFormat('Y-m-d H:i', "{$request->selected_day} {$request->selected_time}");
|
||||
|
||||
$uuidToIgnore = $order->id ? Uuid::fromString($order->id) : null;
|
||||
|
||||
// ? The time slot is different than the already selecte one and the creneau is available ?
|
||||
if (
|
||||
$timeslot and
|
||||
$timeslot->slot->notEqualTo($creneau) and
|
||||
!$shop->isCreneauAvailable($creneau, $uuidToIgnore)
|
||||
) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => 'Ce créneau n\'est plus disponible'
|
||||
]);
|
||||
}
|
||||
$this->assertDeliveryModeIsValid();
|
||||
|
||||
DB::transaction(function () use ($order, $shop, $creneau) {
|
||||
// * Assign order id we would use, if none already.
|
||||
if (!$order->id) {
|
||||
$order->id = Str::uuid();
|
||||
}
|
||||
|
||||
// * Remove other timeslots for this order.
|
||||
Timeslot::query()->where('order_id', $order->id)->forceDelete();
|
||||
|
||||
/** @var \App\Models\Shop\Timeslot */
|
||||
$timeSlot = Timeslot::query()->whereHas('order', function (Builder $q) use ($order) {
|
||||
$q->where('id', $order->id);
|
||||
})->firstOrNew();
|
||||
$timeSlot->order()->associate($order);
|
||||
$timeSlot->shop()->associate($shop);
|
||||
$timeSlot->slot = $creneau;
|
||||
$timeSlot->save();
|
||||
|
||||
$order->timeslot()->save($timeSlot);
|
||||
$order->setRelation('timeslot', $timeSlot);
|
||||
Session::put('currentOrder', $order);
|
||||
|
||||
self::allowTimeSlotSelect(true);
|
||||
});
|
||||
return response()->redirectToRoute('order-tunnel.shipping');
|
||||
}
|
||||
|
||||
/**
|
||||
* SaveShippingAdress
|
||||
*
|
||||
* * --- 3 ---
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Orders\ShippingFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \RuntimeException If somehow no email can be found.
|
||||
*/
|
||||
public function shippingSubmit(ShippingFormRequest $request)
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertDoesHaveCurrentOrder();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertBasketHasMinAmount();
|
||||
$this->assertDeliveryModeIsValid();
|
||||
$this->setOrderProcessStep(OrderProcess::shippment(), OrderProcess::shippingMethod());
|
||||
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
|
||||
$order->fill($request->validated());
|
||||
|
||||
/** @var object */
|
||||
$billing = $order->billing;
|
||||
$billing->country = Country::france();
|
||||
$order->billing = $billing;
|
||||
|
||||
self::allowTimeSlotSelect();
|
||||
|
||||
// Fetch right email to send in.
|
||||
$order->email = $order->billing->email ??
|
||||
$order->shipping->email ??
|
||||
$order->customer->api_data->email;
|
||||
|
||||
if (!$order->email) {
|
||||
throw new \RuntimeException('Somehow no email was provided');
|
||||
}
|
||||
|
||||
$this->fillShippingFromShopInfo($order);
|
||||
|
||||
// * Allow timeslot select
|
||||
Session::put('currentOrder', $order);
|
||||
|
||||
return \response()->redirectToRoute('order-tunnel.review');
|
||||
}
|
||||
|
||||
/**
|
||||
* Valider le panier avant achat.
|
||||
*
|
||||
* * --- 4 ---
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function review()
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertBasketHasMinAmount();
|
||||
$this->assertDoesHaveCurrentOrder();
|
||||
$this->assertDeliveryModeIsValid();
|
||||
$this->setOrderProcessStep(OrderProcess::paymentReview(), OrderProcess::shippment());
|
||||
|
||||
self::allowTimeSlotSelect();
|
||||
|
||||
/** @var \App\Models\Customer\Customer $customer */
|
||||
$customer = auth('frontend')->user();
|
||||
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
|
||||
// * Order completed email already sent.
|
||||
if ($order->mail_sent) {
|
||||
self::destroyCurrentBasket();
|
||||
$message = trans(
|
||||
'Votre commande est déjà prise en compte, veuillez vérifier votre boite e-mail ou votre espace client.'
|
||||
);
|
||||
return \view('theme::pages.order-tunnel.done', \compact('order', 'message'));
|
||||
}
|
||||
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
$availablePaymentModes = app('PaymentModesGlobal')->where('status', true);
|
||||
|
||||
return view('theme::pages.order-tunnel.review', \compact('basket', 'order', 'availablePaymentModes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Order for submit
|
||||
*
|
||||
* * --- 4 ---
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Orders\CheckoutRequest $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @throws \RuntimeException If payment method is unhandled somehow.
|
||||
*/
|
||||
public function reviewSubmit(CheckoutRequest $request): Response
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertBasketDidNotChange();
|
||||
$this->assertDoesHaveCurrentOrder();
|
||||
$this->assertDeliveryModeIsValid();
|
||||
$this->setOrderProcessStep(OrderProcess::paymentReview(), OrderProcess::shippment());
|
||||
|
||||
/** @var \App\Models\Customer\Customer $customer */
|
||||
$customer = auth('frontend')->user();
|
||||
|
||||
// * Force clone here to prevent session save model state (If something goes wrong).
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = clone Order::getCurrentOrder();
|
||||
|
||||
// * Order completed email already sent.
|
||||
if (!$order->exists and $order->mail_sent) {
|
||||
self::destroyCurrentBasket();
|
||||
$message = trans(
|
||||
'Votre commande est déjà prise en compte, veuillez vérifier votre boite e-mail ou votre espace client.'
|
||||
);
|
||||
return \view('theme::pages.order-tunnel.done', \compact('order', 'message'));
|
||||
}
|
||||
|
||||
/** @var \App\Enums\Order\PaymentModeEnum */
|
||||
$paymentMode = $request->modeEnum;
|
||||
|
||||
// * Check Payment mode
|
||||
Gate::authorize('isAvailable', [PaymentMode::class, $paymentMode]);
|
||||
|
||||
// * Get Transaction
|
||||
$transaction = clone (Transaction::getCurrentTransaction() ??
|
||||
Transaction::getNewInstance(
|
||||
$paymentMode,
|
||||
TransactionType::debit(),
|
||||
$order->basket,
|
||||
$order->total_ttc,
|
||||
));
|
||||
if ($transaction->exists) {
|
||||
$transaction->refresh();
|
||||
}
|
||||
|
||||
// * If transaction is already payed.
|
||||
if ($transaction->status->equals(TransactionStatus::validated())) {
|
||||
// ! Prevent double checkout (double transaction), just let IPN (webhooks) handle this.
|
||||
$e = new \RuntimeException('La transaction a déjà été traitée');
|
||||
report($e);
|
||||
self::destroyCurrentBasket();
|
||||
abort(500, trans($e->getMessage()));
|
||||
}
|
||||
|
||||
// * If previously failed get a new one.
|
||||
if ($transaction->status->equals(TransactionStatus::failed())) {
|
||||
$transaction = Transaction::getNewInstance(
|
||||
$paymentMode,
|
||||
TransactionType::debit(),
|
||||
$order->basket,
|
||||
$order->total_ttc,
|
||||
);
|
||||
}
|
||||
|
||||
// * If customer switched transaction mode.
|
||||
if (!$transaction->payment_mode->equals($paymentMode)) {
|
||||
// * Reuse previous
|
||||
/** @var \App\Models\Payment\Transaction $transaction */
|
||||
$transaction = Transaction::query()->whereHas('order', function (Builder $q) use ($order) {
|
||||
$q->where('id', $order->id);
|
||||
})->where('payment_mode', $paymentMode)->where('status', TransactionStatus::pending())
|
||||
->first() ?? Transaction::getNewInstance(
|
||||
$paymentMode,
|
||||
TransactionType::debit(),
|
||||
$order->basket,
|
||||
$order->total_ttc,
|
||||
);
|
||||
// * Remove other pending in shop transactions
|
||||
Transaction::query()->whereHas('order', function (Builder $q) use ($order) {
|
||||
$q->where('id', $order->id);
|
||||
})->where('status', TransactionStatus::pending())->where('id', '!=', $transaction->id)
|
||||
->where('payment_mode', PaymentModeEnum::inShop())->delete();
|
||||
}
|
||||
|
||||
// * If payment mode is boutique just use the previous transaction if there was one.
|
||||
/** @var \App\Models\Payment\Transaction $transaction */
|
||||
if ($transaction->payment_mode->equals(PaymentModeEnum::inShop())) {
|
||||
/** @var \App\Models\Payment\Transaction $transaction */
|
||||
$transaction = Transaction::query()->whereHas('order', function (Builder $q) use ($order) {
|
||||
$q->where('id', $order->id);
|
||||
})->where('payment_mode', PaymentModeEnum::inShop())
|
||||
->where('status', TransactionStatus::pending())->first() ?? $transaction;
|
||||
}
|
||||
|
||||
// * Checkout using selected Payment system.
|
||||
/** @var \App\Models\Payment\Transaction $transaction */
|
||||
return $transaction->getAdapter()->checkout(
|
||||
$customer,
|
||||
$order,
|
||||
$transaction,
|
||||
// * When succeeded
|
||||
$this->checkoutSucceeded(),
|
||||
// ! If failed.
|
||||
function () {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => trans('Une erreur est survenue, veuillez réssayer')
|
||||
]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkout succeeded event
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
private function checkoutSucceeded(): \Closure
|
||||
{
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
return function (Customer $customer, Order $order, Transaction $transaction): void {
|
||||
// * Associate transaction to order
|
||||
$transaction->order()->associate($order);
|
||||
|
||||
// * Enregistrement commande avant checkout.
|
||||
if (!$order->save() or !$transaction->save()) {
|
||||
report(new \RuntimeException("Order saving error happened."));
|
||||
throw ValidationException::withMessages([
|
||||
'error' => trans('Une erreur est survenue, veuillez réssayer')
|
||||
]);
|
||||
}
|
||||
|
||||
// * Save Transaction
|
||||
Session::put('currentTransaction', $transaction);
|
||||
// * Save Order
|
||||
Session::put('currentOrder', $order);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirection après paiement et validation
|
||||
*
|
||||
* * --- 5 ---
|
||||
*
|
||||
* ! Middleware Url signée ici que pour in shop.
|
||||
*
|
||||
* * La méthode sers a récupérer la session après redirection du module de paiement.
|
||||
*
|
||||
* @param \App\Models\Payment\Transaction $transaction
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function checkout(Transaction $transaction)
|
||||
{
|
||||
/** @var \App\Models\Customer\Customer|null $customer */
|
||||
$customer = auth('frontend')->user();
|
||||
/** @var \App\Models\Shop\Order|null $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
/** @var \App\Models\Payment\Transaction|null $sessionTransaction */
|
||||
$sessionTransaction = Transaction::getCurrentTransaction();
|
||||
|
||||
if (!$customer or !$order or !$sessionTransaction) {
|
||||
\redirect()->route('order-tunnel.review')
|
||||
->with('warning', trans('La session est requise'))
|
||||
->throwResponse();
|
||||
}
|
||||
|
||||
// ? Mismatch between url transaction and session transaction ?
|
||||
// * Needed for stripe IP in route anyway.
|
||||
if ($sessionTransaction->id !== $transaction->id) {
|
||||
\redirect()->route('order-tunnel.review')
|
||||
->with('error', trans('Erreur mauvaise transaction'))
|
||||
->throwResponse();
|
||||
}
|
||||
|
||||
// * Force clone here to prevent session save model state (If something goes wrong).
|
||||
$order = clone $order;
|
||||
$transaction = clone $transaction;
|
||||
|
||||
if (!($transaction = $transaction->getAdapter()->checkoutIsResponseIsValid($customer, $transaction))) {
|
||||
\abort(400, trans('Impossible de valider la transaction'));
|
||||
}
|
||||
|
||||
$transaction->saveOrFail();
|
||||
$transaction->refresh();
|
||||
$transaction->mutateOrderStatus();
|
||||
$order->refresh();
|
||||
|
||||
OrderIsCreated::dispatch($transaction->order);
|
||||
|
||||
// * Save Transaction
|
||||
Session::put('currentTransaction', $transaction);
|
||||
// * Save Order
|
||||
Session::put('currentOrder', $order);
|
||||
|
||||
return view('back::pages.order-tunnel-checkout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirection après paiement et validation
|
||||
*
|
||||
* * --- 5 ---
|
||||
*
|
||||
* * La méthode sers a récupérer la session après redirection du module de paiement.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function checkoutVerify()
|
||||
{
|
||||
$this->assertDoesNotHaveEmptyBasket();
|
||||
$this->assertDoesHaveCurrentOrder();
|
||||
$this->assertDoesHaveCurrentTransaction();
|
||||
if (!$this->checkThatActualProcessStepIs(OrderProcess::paymentReview())) {
|
||||
\redirect()->route('order-tunnel.review')
|
||||
->with('warning', trans('Étape précédente requise'))
|
||||
->throwResponse();
|
||||
}
|
||||
|
||||
return DB::transaction(function () {
|
||||
/** @var \App\Models\Customer\Customer $customer */
|
||||
$customer = auth('frontend')->user();
|
||||
|
||||
// * Force clone here to prevent session save model state (If something goes wrong).
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = clone Order::getCurrentOrder();
|
||||
|
||||
// * Force clone here to prevent session save model state (If something goes wrong).
|
||||
/** @var \App\Models\Payment\Transaction $transaction */
|
||||
$transaction = clone Transaction::getCurrentTransaction();
|
||||
$transaction->refresh();
|
||||
|
||||
$message = trans('Une fois votre commande validée, vous recevrez un email de confirmation.');
|
||||
|
||||
// * Si le payment ne se fait pas en boutique est que la transaction n'est pas validée.
|
||||
// FIXME: Validate Stripe only by IPN ?
|
||||
if (
|
||||
$transaction->payment_mode->equals(PaymentModeEnum::stripe()) and
|
||||
!$transaction->status->equals(TransactionStatus::validated())
|
||||
) {
|
||||
\redirect()->route('order-tunnel.review')
|
||||
->with('error', trans('Le payment n\'as pu être validé'))
|
||||
->throwResponse();
|
||||
}
|
||||
|
||||
if ($transaction->payment_mode->equals(PaymentModeEnum::stripe())) {
|
||||
$message = trans('Votre commande à été validée, vous allez recevoir un email de confirmation.');
|
||||
}
|
||||
if ($transaction->payment_mode->equals(PaymentModeEnum::systemPay())) {
|
||||
$message = trans('Une fois votre commande validée, vous recevrez un email de confirmation.');
|
||||
}
|
||||
|
||||
OrderIsPaid::dispatchIf(
|
||||
!$transaction->payment_mode->equals(PaymentModeEnum::inShop()) and
|
||||
$transaction->status->equals(TransactionStatus::validated()),
|
||||
$transaction->order,
|
||||
$transaction
|
||||
);
|
||||
|
||||
self::destroyCurrentBasket();
|
||||
|
||||
return view('theme::pages.order-tunnel.done', \compact('order', 'message'));
|
||||
});
|
||||
}
|
||||
|
||||
// * --- FIN TUNNEL DE COMMANDE ---
|
||||
// * PRIVATE METHODS
|
||||
|
||||
/**
|
||||
* Allow timeslot select in the tunnel even if already selected
|
||||
*
|
||||
* @param boolean $disallow To force disallow timeslot picker select.
|
||||
* @return void
|
||||
*/
|
||||
private function allowTimeSlotSelect(bool $disallow = false): void
|
||||
{
|
||||
// * Allow timeslot select
|
||||
Session::put('deliveryModePickSlot', $disallow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is allowed to select timesSlot ?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private static function allowedTimeSlotSelect(): bool
|
||||
{
|
||||
return (bool)Session::get('deliveryModePickSlot');
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert user does not have an empty basket
|
||||
* or redirect with warning
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function assertDoesHaveCurrentOrder()
|
||||
{
|
||||
if (
|
||||
$order = Order::getCurrentOrder() and
|
||||
$order->payment_status and
|
||||
$order->payment_status->equals(PaymentStatus::payed())
|
||||
) {
|
||||
self::destroyCurrentBasket();
|
||||
$message = trans(
|
||||
'Votre commande est déjà validée, veuillez vérifier votre boite e-mail ou votre espace client.'
|
||||
);
|
||||
\response()->view('theme::pages.order-tunnel.done', \compact('order', 'message'))->throwResponse();
|
||||
}
|
||||
|
||||
if (!$order) {
|
||||
\redirect()->route('order-tunnel.basket.recap')->throwResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete order steps, removes basket, ends tunnel transaction.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function destroyCurrentBasket()
|
||||
{
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
$basket->destroy();
|
||||
|
||||
// * Remove timeslot if order is not saved into DB.
|
||||
/** @var \App\Models\Shop\Order|null */
|
||||
if ($order = Session::get('currentOrder') and $order->timeslot and !$order->exists) {
|
||||
$order->timeslot->forceDelete();
|
||||
}
|
||||
|
||||
Session::remove('currentOrder');
|
||||
Session::remove('currentTransaction');
|
||||
Session::remove('PreviousOrderStep');
|
||||
Session::remove('OrderStep');
|
||||
Session::remove('deliveryModePickSlot');
|
||||
Session::remove('basketFingerPrint');
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert user does not have an empty basket
|
||||
* or redirect with warning
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function assertDoesNotHaveEmptyBasket(): void
|
||||
{
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
|
||||
if (!$basket->count()) {
|
||||
\redirect()->route('home')
|
||||
->with('warning', trans('Vous n\'avez aucun produit dans votre panier'))
|
||||
->throwResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert user does not have an empty basket
|
||||
* or redirect with warning
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function assertBasketDidNotChange(): void
|
||||
{
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
$actual_finger_print = hash('sha256', \json_encode($basket->content()->jsonSerialize()));
|
||||
$session_finger_print = Session::get('basketFingerPrint');
|
||||
|
||||
Session::put('basketFingerPrint', $actual_finger_print);
|
||||
|
||||
if ($session_finger_print !== $actual_finger_print) {
|
||||
$this->allowTimeSlotSelect(true);
|
||||
\redirect()->route('order-tunnel.basket.recap')
|
||||
->with('warning', trans('Votre panier à été modifié'))
|
||||
->throwResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert basket has the minimal amount required for payment
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function assertBasketHasMinAmount(): void
|
||||
{
|
||||
/** @var \Gloudemans\Shoppingcart\Cart */
|
||||
$basket = app('basket');
|
||||
$sampleOrder = new Order();
|
||||
$sampleOrder->assignBasket($basket);
|
||||
$minAmountForTransaction = \collect(PaymentModeEnum::toArray())
|
||||
->max(function (PaymentModeEnum $paymentMode) {
|
||||
return $paymentMode->minAmount;
|
||||
});
|
||||
if ($sampleOrder->total_ttc < $minAmountForTransaction) {
|
||||
\redirect()->route('home')
|
||||
->with('warning', trans('Le montant minimal pour une commande est de :minAmount', [
|
||||
'minAmount' => ToolboxHelper::fmtCurrency($minAmountForTransaction)
|
||||
]))->throwResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert user does not have an empty basket
|
||||
* or redirect with warning
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function assertDoesHaveCurrentTransaction()
|
||||
{
|
||||
$transaction = Transaction::getCurrentTransaction();
|
||||
if (
|
||||
!$transaction or ($transaction->status and
|
||||
$transaction->status->equals(TransactionStatus::failed())
|
||||
)
|
||||
) {
|
||||
\redirect()->route('order-tunnel.review')
|
||||
->with('warning', trans('La transaction a échoué'))
|
||||
->throwResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert delivery mode si still available.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function assertDeliveryModeIsValid(): void
|
||||
{
|
||||
$order = Order::getCurrentOrder();
|
||||
if (!Gate::check('orderUsingDeliveryMode', $order)) {
|
||||
$this->allowTimeSlotSelect(true);
|
||||
\redirect()->route('order-tunnel.shipping-mode')
|
||||
->with('warning', trans('Le mode de livraison n\'est pas disponible'))
|
||||
->throwResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Process step
|
||||
*
|
||||
* @param \App\Enums\Order\OrderProcess $step
|
||||
* @param \App\Enums\Order\OrderProcess|null $assertDid
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException If previous was not done.
|
||||
*/
|
||||
private function setOrderProcessStep(OrderProcess $step, OrderProcess $assertDid = null): void
|
||||
{
|
||||
if ($assertDid) {
|
||||
if (!Session::get('PreviousOrderStep')) {
|
||||
Session::put('PreviousOrderStep', collect());
|
||||
}
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
$previousSteps = Session::get('PreviousOrderStep');
|
||||
if (Session::get('OrderStep') < $step) {
|
||||
/** @var \App\Enums\OrderProcess */
|
||||
$previousStep = Session::get('OrderStep');
|
||||
$previousSteps->put($previousStep->value, $previousStep);
|
||||
Session::put('PreviousOrderStep', $previousSteps);
|
||||
}
|
||||
$this->assertDidProcessStep($assertDid);
|
||||
} //end if
|
||||
|
||||
Session::put('OrderStep', $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert the the step is done.
|
||||
*
|
||||
* @param \App\Enums\Order\OrderProcess $assertDid
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException If previous was not done.
|
||||
*/
|
||||
private function assertDidProcessStep(OrderProcess $assertDid): void
|
||||
{
|
||||
if (!Session::get('PreviousOrderStep')) {
|
||||
Session::put('PreviousOrderStep', collect());
|
||||
}
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
$previousSteps = Session::get('PreviousOrderStep');
|
||||
|
||||
if (!$previousSteps->count()) {
|
||||
\redirect()->route('home')
|
||||
->with('warning', trans('Vous devez d\'abord valider votre panier'))
|
||||
->throwResponse();
|
||||
}
|
||||
if (!$previousSteps->contains($assertDid)) {
|
||||
throw ValidationException::withMessages(['Étape précédente requise']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert the actual step is.
|
||||
*
|
||||
* @param \App\Enums\Order\OrderProcess $assertActual
|
||||
* @return boolean
|
||||
* @throws \Illuminate\Validation\ValidationException If previous was not done.
|
||||
*/
|
||||
private function checkThatActualProcessStepIs(OrderProcess $assertActual): bool
|
||||
{
|
||||
/** @var \App\Enums\OrderProcess|null */
|
||||
$orderStep = Session::get('OrderStep');
|
||||
return $orderStep and $orderStep->equals($assertActual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill order shipping with in shop infos
|
||||
*
|
||||
* @param \App\Models\Shop\Order $order
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException Si le créneau de reservation n'est plus trouvable.
|
||||
*/
|
||||
private function fillShippingFromShopInfo(Order $order)
|
||||
{
|
||||
if ($order->deliveryMode->mode->equals(DeliveryModeEnum::inShop())) {
|
||||
/** @var \App\Models\Shop\Timeslot|null */
|
||||
if (!($timeslot = $order->timeslot()->first())) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => trans('Créneau de réservation introuvable')
|
||||
]);
|
||||
}
|
||||
$order->shipping = [
|
||||
'firstname' => $timeslot->shop->name,
|
||||
'lastname' => '',
|
||||
'email' => null,
|
||||
'phone' => $timeslot->shop->phone,
|
||||
'line1' => $timeslot->shop->address,
|
||||
'postal_code' => $timeslot->shop->postal_code,
|
||||
'city' => $timeslot->shop->city,
|
||||
'country' => $timeslot->shop->country
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
66
app/Http/Controllers/Fo/ProductController.php
Normal file
66
app/Http/Controllers/Fo/ProductController.php
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Merchandise\Product;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* One product page
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $productSlug
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function product(Product $productSlug)
|
||||
{
|
||||
return view('theme::pages.products.show', ['productModel' => $productSlug]);
|
||||
}
|
||||
|
||||
/**
|
||||
* All products.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
$products = Product::query()->where('status', 1)->with(['discount'])->paginate(12);
|
||||
|
||||
return view('theme::pages.products.index', compact('products'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Product card.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Product $product
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function ajaxProductsCard(Product $product)
|
||||
{
|
||||
return view('theme::partials.products.card', ['product' => $product]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche par nom de produit.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
*/
|
||||
public function searchProducts(Request $request)
|
||||
{
|
||||
$filter = \htmlentities($request->query('filter'));
|
||||
$products = Product::query()->where('status', true)
|
||||
->when(!empty($filter), function (Builder $q) use ($filter) {
|
||||
$q->where('name', 'like', "%{$filter}%");
|
||||
})->with(['discount'])->paginate(12);
|
||||
|
||||
$search_title = 'Recherche : ' . $filter;
|
||||
|
||||
return view('theme::pages.search', compact('products', 'search_title', 'filter'));
|
||||
}
|
||||
}
|
||||
55
app/Http/Controllers/Fo/RangeController.php
Normal file
55
app/Http/Controllers/Fo/RangeController.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Merchandise\Product;
|
||||
use App\Models\Merchandise\Range;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class RangeController extends Controller
|
||||
{
|
||||
/**
|
||||
* All ranges.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function ranges()
|
||||
{
|
||||
// $ranges shared in AppServiceProvider.
|
||||
return view('theme::pages.ranges.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* One Range page.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Range $rangeSlug
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function range(Range $rangeSlug)
|
||||
{
|
||||
$products = Product::query()->whereHas('range', function (Builder $q) use ($rangeSlug) {
|
||||
$q->where('id', $rangeSlug->id);
|
||||
})->where('status', true)->with('discount')->paginate(9);
|
||||
// * Find promo within range.
|
||||
$offres = Product::query()->whereHas('range', function (Builder $q) use ($rangeSlug) {
|
||||
$q->where('id', $rangeSlug->id);
|
||||
})->where('status', true)->has('discount')->with('discount')->get();
|
||||
return view('theme::pages.ranges.show', [
|
||||
'range' => $rangeSlug,
|
||||
'products' => $products,
|
||||
'offres' => $offres
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Range card.
|
||||
*
|
||||
* @param \App\Models\Merchandise\Range $range
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function ajaxRangesCard(Range $range)
|
||||
{
|
||||
return view('theme::partials.ranges.card', ['range' => $range]);
|
||||
}
|
||||
}
|
||||
89
app/Http/Controllers/Fo/StaticPageController.php
Normal file
89
app/Http/Controllers/Fo/StaticPageController.php
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Enums\StaticPageType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Merchandise\Product;
|
||||
use App\Models\Site\Slide;
|
||||
use App\Models\Site\StaticPage;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StaticPageController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display static page type home
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function home()
|
||||
{
|
||||
$content = StaticPage::getPageOfType(StaticPageType::home());
|
||||
// * Star products.
|
||||
$products = Product::where('status', true)->where('star', true)->get();
|
||||
|
||||
$slides = Slide::query()->where('status', true)->get();
|
||||
|
||||
return view(
|
||||
'theme::pages.home',
|
||||
compact('content', 'products', 'slides')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a static page
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function displayCrudStaticPageIndex()
|
||||
{
|
||||
return \view('theme::pages.static-page-index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a static page
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\Models\Site\StaticPage $static_page_front
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
* @throws \RuntimeException If the static page type is not handled.
|
||||
*/
|
||||
public function displayStaticPage(Request $request, StaticPage $static_page_front)
|
||||
{
|
||||
$static_page = $static_page_front;
|
||||
switch ($static_page->type) {
|
||||
case StaticPageType::contact():
|
||||
return app(ContactController::class)->contact($request);
|
||||
case StaticPageType::legals():
|
||||
case StaticPageType::sellconditions():
|
||||
case StaticPageType::confidentiality():
|
||||
case StaticPageType::faq():
|
||||
return view('theme::pages.static-page', compact('static_page'));
|
||||
case StaticPageType::crud():
|
||||
case StaticPageType::home():
|
||||
default:
|
||||
if (\config('app.debug')) {
|
||||
throw new \RuntimeException("Unhandled static page {$static_page->type->label}");
|
||||
}
|
||||
\abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a crud static page
|
||||
*
|
||||
* @param \App\Models\Site\StaticPage $static_page
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
* @throws \RuntimeException If the static page type is not handled.
|
||||
*/
|
||||
public function displayCrudStaticPage(StaticPage $static_page)
|
||||
{
|
||||
if (!$static_page->type->equals(StaticPageType::crud())) {
|
||||
if (\config('app.debug')) {
|
||||
throw new \RuntimeException("Unhandled static page {$static_page->type->label}");
|
||||
}
|
||||
\abort(404);
|
||||
}
|
||||
return view('theme::pages.static-page', compact('static_page'));
|
||||
}
|
||||
}
|
||||
43
app/Http/Controllers/Fo/TagController.php
Normal file
43
app/Http/Controllers/Fo/TagController.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Merchandise\Product;
|
||||
use App\Models\Merchandise\Tag;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
* All tags.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
*/
|
||||
public function tags()
|
||||
{
|
||||
$tags = Tag::query()->where('status', true)
|
||||
->with(['products'])->paginate(12);
|
||||
|
||||
return view('theme::pages.tags.index', compact('tags'));
|
||||
}
|
||||
|
||||
/**
|
||||
* One tag page,
|
||||
* products filtered by tag
|
||||
*
|
||||
* @param \App\Models\Merchandise\Tag $tag
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function tag(Tag $tag)
|
||||
{
|
||||
$products = Product::query()
|
||||
->where('status', true)
|
||||
->with(['discount'])
|
||||
->whereHas('tags', function ($q) use ($tag) {
|
||||
$q->where('id', $tag->id);
|
||||
})->paginate(12);
|
||||
|
||||
return view('theme::pages.tags.show', compact('products', 'tag'));
|
||||
}
|
||||
}
|
||||
26
app/Http/Controllers/Fo/TimeSlotController.php
Normal file
26
app/Http/Controllers/Fo/TimeSlotController.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Models\Shop\Order;
|
||||
use App\Models\Shop\Shop;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
class TimeSlotController
|
||||
{
|
||||
/**
|
||||
* Récupérer tout les créneaux disponible à partir de
|
||||
* maintenant pour un magasin sur les jours à venir.
|
||||
*
|
||||
* @param \App\Models\Shop\Shop $shop Le magasin concerné.
|
||||
* @return array
|
||||
* @throws \RuntimeException Si la période demandé est incohérente.
|
||||
*/
|
||||
public function getAvailableCreneauxByShop(Shop $shop)
|
||||
{
|
||||
/** @var \App\Models\Shop\Order $order */
|
||||
$order = Order::getCurrentOrder();
|
||||
return $shop->getAvailableCreneaux(null, $order->id ?
|
||||
Uuid::fromString($order->id) : null);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Content;
|
||||
use App\Models\Product;
|
||||
use App\Models\Slider;
|
||||
use App\Models\Range;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use LDC\LDCCRM\Enums\ApiError;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\CrmException;
|
||||
use LDC\LDCCRM\Models\SingleOptin;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display homepage
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// @phpcs:enable
|
||||
$content = Content::where('key', 'accueil')->first();
|
||||
// Star products.
|
||||
$products = Product::where('status', 1)->where('star', 1)->get();
|
||||
|
||||
$slider = Slider::where('slug', 'home')->first();
|
||||
$slides = $slider->showableSlides;
|
||||
|
||||
$quickorder_ranges = Range::with('products')->get();
|
||||
foreach ($quickorder_ranges as $range) {
|
||||
foreach ($range->products as $product) {
|
||||
$product->calculatedPrices = $product->getCalcPrices();
|
||||
}
|
||||
}
|
||||
|
||||
return view('home', compact('content', 'products', 'slides', 'quickorder_ranges'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the CRM to add a single optin
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
*/
|
||||
public function addOptIn(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), ['email' => 'required|email']);
|
||||
if ($validator->fails()) {
|
||||
return __('L\'adresse email est incorrecte');
|
||||
}
|
||||
|
||||
try {
|
||||
SingleOptin::setStatus($request->email, true);
|
||||
return trans('Votre inscription à la newsletter a été prise en compte');
|
||||
} catch (ApiErrorException $e) {
|
||||
// * Il y a deja un customerInfo avec optin a true pour ce customer
|
||||
if ($e->getApiError()->equals(ApiError::singleOptinCustomerExists())) {
|
||||
return trans('Vous êtes déjà inscrit avec cette adresse email');
|
||||
}
|
||||
report($e);
|
||||
return trans('Une erreur est survenue, merci de réessayer ultérieurement');
|
||||
} catch (CrmException $e) {
|
||||
report($e);
|
||||
return trans('Une erreur est survenue, merci de réessayer ultérieurement');
|
||||
}
|
||||
return trans('Une erreur est survenue, merci de réessayer ultérieurement ');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue