Compare commits

...

785 commits

Author SHA1 Message Date
K Muller
5634d4d232 Merge branch 'trunk' 2026-10-15 09:12:44 +02:00
K Muller
9a1a07307b Merge branch 'develop' into trunk 2026-10-15 09:12:16 +02:00
Karl M'muller
8410447a29 Merge branch '134-restore-soft-delete' into 'develop'
feat: ✨ restore soft-deleted user on create

See merge request ldc-web/projets/support-web!138
2026-10-15 07:11:08 +00:00
Corentin Huet
f0fb7a26f3 feat: ✨ restore soft-deleted user on create 2026-10-08 15:31:11 +02:00
Noah Lancien
f55ca959b8 Merge branch 'trunk' 2026-10-07 15:30:35 +02:00
Noah Lancien
d622f543e9 Merge branch 'develop' into trunk 2026-10-07 15:29:51 +02:00
Noix
1f1c684008 Merge branch '133-export-file' into 'develop'
feat: ✨ change ExportTicketsState to Friday 14:00

See merge request ldc-web/projets/support-web!137
2026-10-07 13:20:45 +00:00
Corentin Huet
e8c5472d45 feat: ✨ change ExportTicketsState to Friday 14:00 2026-10-07 09:30:01 +02:00
Noah Lancien
4ff19d9277 Merge branch 'trunk' 2026-10-01 10:07:26 +02:00
Noah Lancien
7dfd80cf23 Merge branch 'develop' into trunk 2026-10-01 10:07:12 +02:00
Noix
e19d810a2f Merge branch '132-create-gitlab-issue' into 'develop'
feat: ✨ allow creating gitlab issues for mailing type

See merge request ldc-web/projets/support-web!136
2026-10-01 08:06:30 +00:00
Corentin Huet
ab998c975d feat: ✨ allow creating gitlab issues for mailing type 2026-09-01 16:51:04 +02:00
Vincent BRIDIER
9706922312 Merge branch 'trunk' 2026-08-27 20:56:21 +02:00
Vincent BRIDIER
ebb52b5968 Merge branch 'develop' into trunk 2026-08-27 20:56:07 +02:00
Vincent BRIDIER
6c783247a7 fix: Alpine www-data = 82 2026-08-27 20:54:40 +02:00
K Muller
6cf790feab Merge branch 'trunk' 2026-08-26 12:58:54 +02:00
K Muller
57c7613455 Merge branch 'develop' into trunk 2026-08-26 12:58:41 +02:00
Karl M'muller
eddeb4f7f6 Merge branch '128-archived-project' into 'develop'
fix: 🐛 add error message for archived project

See merge request ldc-web/projets/support-web!135
2026-08-26 10:58:10 +00:00
Karl M'muller
d9d1fea624 Merge branch '127-error-sentry' into 'develop'
fix: 🐛 update regex to match both issue and work items

See merge request ldc-web/projets/support-web!134
2026-08-26 10:57:57 +00:00
Corentin Huet
22d79cfb11 fix: 🐛 add error message for archived project 2026-08-25 13:16:11 +02:00
Corentin Huet
22bc49baab fix: 🐛 update regex to match both issue and work items 2026-08-24 17:50:16 +02:00
K Muller
adb2a8b21c Merge branch 'trunk' 2026-07-23 09:26:12 +02:00
K Muller
7246d7894d Merge branch 'develop' into trunk 2026-07-23 09:25:13 +02:00
Karl M'muller
10b75031e7 Merge branch 'issue-126' into 'develop'
Fix: 🐛 duplicate emails sent when a ticket's modif is changed

See merge request ldc-web/projets/support-web!133
2026-07-23 07:23:38 +00:00
Abdel LAMRANI
68a48fdf5a Fix: 🐛 duplicate emails sent when a ticket's modif is changed 2026-07-20 12:45:46 +02:00
Jeremy Munsch
a7debacd65
Merge branch 'trunk' 2026-06-26 15:36:53 +02:00
Jeremy Munsch
dd10d4ba3a
Merge branch 'develop' into trunk 2026-06-26 15:36:43 +02:00
Jeremy Munsch
a7bd6d6420
fixed: NotifyAdmin event listener 2026-06-26 15:36:34 +02:00
Jeremy Munsch
8cfc409d5c
Merge branch 'trunk' 2026-06-26 15:28:54 +02:00
Jeremy Munsch
bc7a1020bc
Merge branch 'develop' into trunk 2026-06-26 15:28:45 +02:00
Jeremy Munsch
e828c8bf66
fix: TicketCreated event 2026-06-26 15:28:31 +02:00
Jeremy Munsch
f28dbdd1df
Merge branch 'trunk' 2026-06-26 15:15:10 +02:00
Jeremy Munsch
965226fae6
Fixed ticket creation 2026-06-26 15:14:32 +02:00
Jeremy Munsch
bd9b7cd32e
fix: new ticket creation failed 2026-06-26 15:13:48 +02:00
Noah Lancien
8c67989526 Merge branch 'trunk' 2026-06-26 09:50:56 +02:00
Noah Lancien
2212b0ae08 Merge branch 'develop' into trunk 2026-06-26 09:50:41 +02:00
Noix
c2b25c3503 Merge branch 'brevo-fix' into 'develop'
fix: brevo in (content commit that were missed)

See merge request ldc-web/projets/support-web!132
2026-06-26 07:46:25 +00:00
Jeremy Munsch
f106c17588
fix: brevo in (content commit that were missed) 2026-06-26 09:33:50 +02:00
Noah Lancien
8e9d117918 Merge branch 'trunk' 2026-06-25 11:07:30 +02:00
Noah Lancien
0dbb483fc4 Merge branch 'develop' into trunk 2026-06-25 08:47:02 +02:00
Noah Lancien
980717f37c ci: swicth to docker multi-stage 2026-06-25 08:46:44 +02:00
Noah Lancien
020fcdaa03 Merge branch 'develop' into trunk 2026-06-25 08:37:04 +02:00
Noix
095f80eac1 Merge branch 'brevo-webhook-fix' into 'develop'
Brevo webhook fix Closes #106

See merge request ldc-web/projets/support-web!130
2026-06-25 06:36:32 +00:00
Noix
6a973703c4 Merge branch 'issue-124' into 'develop'
refactor: change ldc logo Closes #124

See merge request ldc-web/projets/support-web!131
2026-06-25 06:36:22 +00:00
Jeremy Munsch
9a853088b1
refactor: change ldc logo Closes #124 2026-06-24 17:22:58 +02:00
Jeremy Munsch
0ec3be521d
refactor: Fixes #106 create ticket automatically from brevo webhook manager 2026-06-24 16:46:12 +02:00
Jeremy Munsch
6854af708b
fix: fix project migrations 2026-06-24 13:22:36 +02:00
Noah Lancien
8f1c920e26 Merge branch 'trunk' 2026-05-18 10:28:44 +02:00
Noah Lancien
efe5e8ace6 Merge branch 'develop' into trunk 2026-05-18 10:28:29 +02:00
Noah Lancien
91f4773c60 chore: 📦 Added meow npm package 2026-05-18 10:28:21 +02:00
Noah Lancien
6b5b4ec619 Merge branch 'trunk' 2026-05-18 10:18:39 +02:00
Noah Lancien
4edd92e572 Merge branch 'develop' into trunk 2026-05-18 10:18:20 +02:00
Noix
da03fbe273 Merge branch '115-project-not-found' into 'develop'
fix: 🐛 handle 404 when gitlab project is not found

See merge request ldc-web/projets/support-web!128
2026-05-18 08:12:44 +00:00
Noah Lancien
b7f7b7c55d Merge branch 'trunk' 2026-04-29 16:28:13 +02:00
Noah Lancien
49d37a8fa6 Merge branch 'develop' into trunk 2026-04-29 16:18:44 +02:00
Noah Lancien
195a5fcb3e chore: arrow_up: Bump PHP 8.5 2026-04-29 16:18:25 +02:00
Noah Lancien
e0af4a243a Merge branch 'trunk' 2026-04-29 16:10:44 +02:00
Noah Lancien
0c4d376c22 Merge branch 'develop' into trunk 2026-04-29 16:10:11 +02:00
Noix
6fabb998ed Merge branch 'support-to-glab-labels' into 'develop'
fix: 🐛 update to-dispatch label to g-to-dispatch

See merge request ldc-web/projets/support-web!129
2026-04-29 14:09:36 +00:00
Corentin Huet
04bd156849 fix: 🐛 update to-dispatch label to g-to-dispatch 2026-04-28 15:16:20 +02:00
Corentin Huet
a43037d2f9 fix: 🐛 handle 404 when gitlab project is not found 2026-03-30 11:59:42 +02:00
Noah Lancien
ef57fe9fe5 Merge branch 'trunk' 2026-03-25 11:52:33 +01:00
Noah Lancien
62901a015e Merge branch 'develop' into trunk 2026-03-25 11:52:18 +01:00
noah.lancien
004af70c30 Merge branch '107-issue-bug' into 'develop'
fix: 🐛 remove duplicate imports

See merge request ldc-web/projets/support-web!127
2026-03-25 10:51:55 +00:00
noah.lancien
c88f3e8d52 Merge branch '90-invoice-filters' into 'develop'
feat: ✨ add awaiting signature/invoicing filters and auto-set...

See merge request ldc-web/projets/support-web!121
2026-03-25 10:48:36 +00:00
Corentin Huet
fb78d5a77d fix: 🐛 remove duplicate imports 2026-03-25 11:48:29 +01:00
noah.lancien
292456bf14 Merge branch '107-issue-bug' into 'develop'
feat: ✨ add to-dispatch label for bug tickets and change default assignee label

See merge request ldc-web/projets/support-web!120
2026-03-25 10:48:12 +00:00
Corentin Huet
a43c6c95b1 feat: ✨ add to-dispatch label for bug tickets and change default assignee label 2026-03-25 11:44:17 +01:00
noah.lancien
9b2248b146 Merge branch '111-add-column' into 'develop'
feat: ✨ add estimate column to tickets page

See merge request ldc-web/projets/support-web!126
2026-03-24 15:49:59 +00:00
noah.lancien
9ea4786aa8 Merge branch '105-sync-gitlab-support' into 'develop'
Resolve "Liaison labels (Gitlab) et statuts (support tickets)"

See merge request ldc-web/projets/support-web!123
2026-03-24 15:48:12 +00:00
noah.lancien
b77c0908f6 Merge branch '87-ticket-status' into 'develop'
feat: ✨ add new status + sync of g-wip label with in development

See merge request ldc-web/projets/support-web!122
2026-03-24 15:47:40 +00:00
Corentin Huet
721e2200f6 feat: ✨ add estimate column to tickets page 2026-03-13 14:44:36 +01:00
Noah Lancien
cbabb40f83 Merge branch 'develop' into trunk 2026-02-26 12:10:44 +01:00
noah.lancien
e71c0546c5 Merge branch '112-feedback' into 'develop'
fix: 🐛 correct default selected status in filter dropdown

See merge request ldc-web/projets/support-web!125
2026-02-26 11:10:02 +00:00
Corentin Huet
ebeccffac6 fix: 🐛 correct default selected status in filter dropdown 2026-02-26 11:59:21 +01:00
Noah Lancien
870986faa4 Merge branch 'develop' into trunk 2026-02-26 11:15:14 +01:00
noah.lancien
da65fcd12c Merge branch '112-unused-packages' into 'develop'
feat: ✨ add published status filter to packages listing

See merge request ldc-web/projets/support-web!124
2026-02-26 10:14:38 +00:00
Corentin Huet
e0e6147576 feat: ✨ add published status filter to packages listing 2026-02-26 10:20:22 +01:00
Corentin Huet
c7493abea0 feat: ✨ sync support statuses with gitlab 2026-02-11 13:34:43 +01:00
Corentin Huet
95b69e9496 feat: ✨ add new status + sync of g-wip label with in development 2026-02-11 13:21:29 +01:00
Corentin Huet
a3123a2bf2 feat: ✨ add awaiting signature/invoicing filters and auto-set archived status on accounting sent date 2026-02-09 09:39:24 +01:00
Noah Lancien
33ea75a5ed Merge branch 'trunk' 2026-01-29 12:38:38 +01:00
Noah Lancien
3e09baf6f3 Merge branch 'develop' into trunk 2026-01-29 12:38:20 +01:00
Noah Lancien
1794076c91 ci: limit jobs history to 1 2026-01-29 12:38:01 +01:00
Noah Lancien
d5f1891764 Merge branch 'trunk' 2026-01-19 09:39:57 +01:00
Noah Lancien
098e40576e Merge branch 'develop' into trunk 2026-01-19 09:39:06 +01:00
noah.lancien
3b93ec45c9 Merge branch 'fix-sentry-error' into 'develop'
fix: 🐛 add null checks for webhook fields

See merge request ldc-web/projets/support-web!119
2026-01-19 08:36:56 +00:00
Corentin Huet
3b7ca55d73 fix: 🐛 add null checks for webhook fields 2026-01-16 17:20:25 +01:00
Noah Lancien
18b66793a0 Merge branch 'trunk' 2026-01-16 15:56:26 +01:00
Noah Lancien
7ee8a2be82 Merge branch 'develop' into trunk 2026-01-16 15:51:31 +01:00
noah.lancien
7e9cba3d2a Merge branch '106-mailing-ticket' into 'develop'
feat: ✨ implement webhook ticket creation with regex extraction

See merge request ldc-web/projets/support-web!118
2026-01-16 14:48:57 +00:00
Corentin Huet
4e275c3b37 feat: ✨ implement webhook ticket creation with regex extraction 2026-01-16 15:21:48 +01:00
Noah Lancien
87cc2dec86 Merge branch 'trunk' 2026-01-12 09:32:52 +01:00
Noah Lancien
ea41e19724 Merge branch 'develop' into trunk 2026-01-12 09:32:32 +01:00
Noah Lancien
37beca9c5e ci: added ci variables to define pod resources 2026-01-12 09:31:48 +01:00
Noah Lancien
7aa279e9e4 feat: updated admin-secure 2026-01-12 09:26:03 +01:00
Vincent BRIDIER
65772aeb1d Merge branch 'trunk' 2026-01-02 15:31:49 +01:00
Vincent BRIDIER
ea6ac998d8 Merge branch 'develop' into trunk 2026-01-02 15:31:35 +01:00
Vincent BRIDIER
b14305553f fix: Some PHPCBF 2026-01-02 15:31:21 +01:00
Vincent BRIDIER
aa9483a155 feat: Add Gitlab some datas sync 2026-01-02 15:30:52 +01:00
Noah Lancien
9bc3d9e5e0 Merge branch 'trunk' 2025-11-28 09:33:55 +01:00
Noah Lancien
f99dac8aab Merge branch 'develop' into trunk 2025-11-21 09:07:52 +01:00
noah.lancien
90f27bf560 Merge branch 'reorder-priority-fix' into 'develop'
fix: reorder tickets priority when one is archived

See merge request ldc-web/projets/support-web!117
2025-11-21 07:59:18 +00:00
Noah Lancien
ccc4ed596a fix: reorder tickets priority when one is archived 2025-11-20 17:04:08 +01:00
Noah Lancien
3f4342f3bb Merge branch 'develop' into trunk 2025-11-20 15:54:16 +01:00
noah.lancien
e67e4b3cef Merge branch '103-priority' into 'develop'
feat: replaced change-order with a new priority system

See merge request ldc-web/projets/support-web!116
2025-11-20 14:51:51 +00:00
Noah Lancien
c09214f59a fix: use increment/decrement instead of loop 2025-11-20 09:55:38 +01:00
Noah Lancien
950b2babdc feat: replaced change-order with a new priority system 2025-11-19 17:45:29 +01:00
Noah Lancien
481c732f3e Merge branch 'trunk' 2025-10-30 12:32:32 +01:00
Noah Lancien
887837dcaf Merge branch 'develop' into trunk 2025-10-30 12:22:06 +01:00
noah.lancien
13cc9d1394 Merge branch '102-fix-title' into 'develop'
fix: remove title field

See merge request ldc-web/projets/support-web!115
2025-10-30 11:19:07 +00:00
Corentin Huet
b97f7f575e fix: remove title field 2025-10-23 12:00:50 +02:00
K Muller
4bdcf60dfa Merge branch 'develop' into trunk 2025-10-23 10:32:31 +02:00
karl.muller
17ee6de791 Merge branch '101-mailing' into 'develop'
feat: ✨ add new ticket type for mass email requests

See merge request ldc-web/projets/support-web!113
2025-10-23 08:30:36 +00:00
karl.muller
460029cf83 Merge branch '102-ticket-name' into 'develop'
feat: ✨ add ticket title to tickets.show

See merge request ldc-web/projets/support-web!114
2025-10-23 08:30:32 +00:00
Corentin Huet
e54c491c2d feat: ✨ add ticket title to tickets.show 2025-10-21 11:33:43 +02:00
Corentin Huet
51f77d3be8 feat: ✨ add new ticket type for mass email requests 2025-10-21 11:15:54 +02:00
Noah Lancien
435d5626ee Merge branch 'trunk' 2025-10-09 11:50:24 +02:00
Noah Lancien
50ba8eaf8a Merge branch 'develop' into trunk 2025-10-09 11:50:12 +02:00
Noah Lancien
365b839f53 ci: added staging-resources.yaml 2025-10-09 11:49:53 +02:00
Noah Lancien
f2a65c85b0 Merge branch 'trunk' 2025-10-09 11:43:15 +02:00
Noah Lancien
1a2fe21212 Merge branch 'develop' into trunk 2025-10-09 11:42:45 +02:00
noah.lancien
4434538cc3 Merge branch 'issue-99' into 'develop'
fix: add automatic retries on deadlocks

See merge request ldc-web/projets/support-web!111
2025-10-09 09:38:21 +00:00
Noah Lancien
d702c02bdb Merge branch 'trunk' 2025-09-18 08:59:45 +02:00
Noah Lancien
b1a6dfb72c Merge branch 'develop' into trunk 2025-09-18 08:58:20 +02:00
noah.lancien
ec62c6d4b5 Merge branch 'issue-98' into 'develop'
feat: add ticket title in mails

See merge request ldc-web/projets/support-web!112
2025-09-18 06:56:43 +00:00
Corentin Huet
0f31e03169 feat: add ticket title in mails 2025-09-16 15:06:12 +02:00
Corentin Huet
849420f966 fix: add automatic retries on deadlocks 2025-09-16 12:19:48 +02:00
Vincent BRIDIER
844928e945 Merge branch 'trunk' 2025-08-22 12:51:32 +02:00
Vincent BRIDIER
3560e6c7f6 Merge branch 'develop' into trunk 2025-08-22 10:28:08 +02:00
Vincent BRIDIER
cc339201f0 Merge branch 'issue-84' into 'develop'
fix: 🐛 add another condition to test if the user subscribe to the ticket in Message.php

See merge request ldc-web/projets/support-web!109
2025-08-22 08:27:05 +00:00
nicolas.demangeat
e47d9a75e6 fix: 🐛 Change relationship management for subscriptions - Close #84 2025-08-22 08:27:05 +00:00
Vincent BRIDIER
4d777f6281 feat: Remove unique for gitlab_id on site - Close #94 2025-08-21 12:41:06 +02:00
Vincent BRIDIER
a3529361b7 Merge branch 'issue-95' into 'develop'
fix: 🚑 add Null coalescing operator in projects index.blade to avoid production error

See merge request ldc-web/projets/support-web!110
2025-08-21 10:28:32 +00:00
Vincent BRIDIER
93a4d54a9e feat: Remove legacy Projects parts 2025-08-21 12:24:42 +02:00
Vincent BRIDIER
46bfa5ef1f feat: Update readme 2025-08-20 14:46:50 +00:00
Nicolas Demangeat
005378de41 fix: 🐛 add cascadeOnDelete to project table and change the Project query in index method in ProjectController 2025-08-19 10:27:36 +02:00
Nicolas Demangeat
ed4b227f9a fix: 🚑 add Null coalescing operator in projects index.blade to avoid production error 2025-08-18 15:29:44 +02:00
Vincent BRIDIER
aa3f507483
Merge branch 'trunk' 2025-08-18 14:16:25 +02:00
Vincent BRIDIER
8a34a30ab4
Merge branch 'develop' into trunk 2025-08-18 14:16:17 +02:00
Vincent BRIDIER
88abac9a5d
fix: Fix Requests 2025-08-18 14:16:06 +02:00
Vincent BRIDIER
9172d75e5d
fix: Fix Requests 2025-08-18 14:15:04 +02:00
Vincent BRIDIER
4a0c556937
Merge branch 'trunk' 2025-08-18 14:03:06 +02:00
Vincent BRIDIER
085028a465
Merge branch 'develop' into trunk 2025-08-18 12:40:48 +02:00
Vincent BRIDIER
21abe7d761
fix: Fix Requests 2025-08-18 12:40:36 +02:00
Vincent BRIDIER
f9ed83ff60
Merge branch 'develop' into trunk 2025-08-18 12:13:24 +02:00
Vincent BRIDIER
df912545e1
feat: Add words blacklist for message and ticket creation 2025-08-18 12:13:04 +02:00
Noah Lancien
1ffb5e5bdd Merge branch 'trunk' 2025-07-10 14:54:56 +02:00
Noah Lancien
c6fcd7cfa6 Merge branch 'develop' into trunk 2025-07-10 13:05:54 +02:00
noah.lancien
8f0a139663 Merge branch 'issue-71-favourite' into 'develop'
feat: choice of favourite site added to settings

See merge request ldc-web/projets/support-web!108
2025-07-10 11:04:02 +00:00
Corentin Huet
7ee190f1d3 feat: choice of favourite site added to settings 2025-07-10 12:49:38 +02:00
Noah Lancien
3d81cd77ce Merge branch 'trunk' 2025-07-09 15:31:20 +02:00
Noah Lancien
fba178b598 Merge branch 'develop' into trunk 2025-07-09 15:23:22 +02:00
noah.lancien
c6e5c5eeb7 Merge branch 'issue-74-format' into 'develop'
feat: allow svg files in tickets

See merge request ldc-web/projets/support-web!107
2025-07-09 13:20:57 +00:00
Corentin Huet
3c035aec9d feat: allow svg files in tickets 2025-07-09 15:08:49 +02:00
Noah Lancien
1f02f86610 Merge branch 'trunk' 2025-06-24 10:31:22 +02:00
Noah Lancien
efb3914e4f Merge branch 'develop' into trunk 2025-06-24 10:31:03 +02:00
noah.lancien
dd230c4516 Merge branch 'issue-92-consumer-tickets' into 'develop'
feat: add complaints enum for tickets

See merge request ldc-web/projets/support-web!106
2025-06-24 08:22:07 +00:00
Noah Lancien
6dd7278c4f feat: add complaints enum for tickets 2025-06-19 17:32:33 +02:00
Noah Lancien
b0f4c37153 Merge branch 'trunk' 2025-06-19 12:09:03 +02:00
Noah Lancien
25ab578c93 Merge branch 'develop' into trunk 2025-06-19 12:01:08 +02:00
Noah Lancien
2d0b300a52 ci: update image version + replace 443 port by 80 in manifest 2025-06-19 12:00:53 +02:00
Noah Lancien
52386bbfd4 Merge branch 'develop' into trunk 2025-06-19 11:48:17 +02:00
noah.lancien
748a5018af Merge branch 'issue-89' into 'develop'
feat: 💩 trying to fix invoices sorting, trying to make the delete cascade for site

See merge request ldc-web/projets/support-web!105
2025-06-19 09:47:47 +00:00
Noah Lancien
fbf4a2f96c fix: MR feedback 2025-06-19 11:46:01 +02:00
Noah Lancien
7089b11c5f fix: linkedTickets() method was called with a wrong name 2025-06-19 11:09:42 +02:00
Nicolas Demangeat
de14d846c5 feat: 💩 trying to fix invoices sorting, trying to make the delete cascade for site 2025-06-18 11:10:46 +02:00
Noah Lancien
d6ed7c1f04 Merge branch 'trunk' 2025-06-16 12:00:47 +02:00
Noah Lancien
5477affb97 Merge branch 'develop' into trunk 2025-06-16 11:52:26 +02:00
noah.lancien
77a7871f3d Merge branch 'issue-89' into 'develop'
fix 🐛 sort display invoices is now OK

See merge request ldc-web/projets/support-web!104
2025-06-16 09:50:42 +00:00
Nicolas Demangeat
c63f2b62e9 fix: 🎨 add condition to have invoiceModels sorted by query string or orderByDesc if no query string in InvoiceController 2025-06-16 10:54:46 +02:00
Nicolas Demangeat
4c8f5f20f7 fix: 🐛 add a default behavior in sortQuery method in Controller.php to have the query orderByDesc if no query string 2025-06-16 09:53:32 +02:00
Nicolas Demangeat
09d84e31fb fix 🐛 sort display invoices is now OK 2025-06-13 16:59:39 +02:00
Vincent BRIDIER
3e199d0f68
Merge branch 'trunk' 2025-05-27 10:30:17 +02:00
Vincent BRIDIER
7564600ace
Merge branch 'develop' into trunk 2025-05-27 10:30:05 +02:00
Vincent BRIDIER
88457bb44a
feat: Add Tickets state export notification 2025-05-27 10:29:56 +02:00
Vincent BRIDIER
ba6f7f8e7b
Merge branch 'trunk' 2025-05-12 15:11:13 +02:00
Vincent BRIDIER
f1eddb1cc2
Merge branch 'develop' into trunk 2025-05-12 15:10:59 +02:00
Vincent BRIDIER
7116c5d41f Merge branch 'issue-83' into 'develop'
fix: 🐛 change the blade condition to display or not the project manager

See merge request ldc-web/projets/support-web!103
2025-05-12 13:10:45 +00:00
Nicolas Demangeat
bc0d61d438 fix: ♻️ remove empty class 2025-05-12 15:09:50 +02:00
Nicolas Demangeat
aa49e077bd fix: 💄 refacto tickets show blade class to display the answer button always on the right 2025-05-12 15:08:05 +02:00
Nicolas Demangeat
a484335112 fix: 🐛 change the blade condition to display or not the project manager 2025-05-12 14:39:36 +02:00
Vincent BRIDIER
658fedd3eb
Merge branch 'trunk' 2025-05-12 11:42:21 +02:00
Vincent BRIDIER
31510149af
Merge branch 'develop' into trunk 2025-05-12 11:41:46 +02:00
Vincent BRIDIER
420947f8e0 Merge branch 'issue-83' into 'develop'
fix: 🐛 respond button is now displayed

See merge request ldc-web/projets/support-web!102
2025-05-12 09:39:59 +00:00
Nicolas Demangeat
17c10a1618 fix: 🐛 respond button is now displayed 2025-05-12 10:45:38 +02:00
Noah Lancien
fb8720d41b Merge branch 'trunk' 2025-04-24 15:02:27 +02:00
Noah Lancien
08afe201f8 Merge branch 'develop' into trunk 2025-04-24 15:02:07 +02:00
noah.lancien
db39f78281 Merge branch '81-gitlab-id-troubles-in-requests' into 'develop'
fix: allow null value for gitlab_id and fix update request for users

See merge request ldc-web/projets/support-web!101
2025-04-24 13:00:47 +00:00
Noah Lancien
ea29760b95 fix: allow null value for gitlab_id and fix update request for users 2025-04-24 14:52:52 +02:00
Noah Lancien
afd8f09d02 Merge branch 'trunk' 2025-04-23 12:11:56 +02:00
Noah Lancien
33cf4f1c93 Merge branch 'develop' into trunk 2025-04-23 12:11:30 +02:00
noah.lancien
83d4d5442f Merge branch 'issue-80' into 'develop'
feat: ✨ you can now edit the sent accounting date even when the date...

See merge request ldc-web/projets/support-web!100
2025-04-23 10:10:31 +00:00
Nicolas Demangeat
e66af8dc92 fix: refacto condition 2025-04-23 11:41:38 +02:00
Nicolas Demangeat
e595c7e145 feat: ✨ you can now edit the sent accounting date even when the date is present if you are admin 2025-04-23 11:12:41 +02:00
Vincent BRIDIER
e1944924c1
Merge branch 'trunk' 2025-04-18 10:28:51 +02:00
Vincent BRIDIER
3a0cc47fa8
Merge branch 'develop' into trunk 2025-04-18 10:14:27 +02:00
Vincent BRIDIER
770cb043c4
feat: Update manifest for db vars 2025-04-18 10:14:12 +02:00
Vincent BRIDIER
3a2b5a0af9
Merge branch 'develop' into trunk 2025-04-18 09:59:53 +02:00
Vincent BRIDIER
f1ddf3b101
feat: Update Ticket linking 2025-04-18 09:58:41 +02:00
Vincent BRIDIER
d9aa989984
feat: Add ticket title to gitlab issue title 2025-04-17 17:09:28 +02:00
Vincent BRIDIER
e12c48b829
feat: Add Gitlab id on user model 2025-04-17 17:05:50 +02:00
Vincent BRIDIER
eba20accc4
fix: Some fixes 2025-04-17 16:24:27 +02:00
Vincent BRIDIER
0bca962de9
feat: Add project manager on site model - Close #79 2025-04-17 16:22:23 +02:00
Vincent BRIDIER
bf6f35fdb1
feat: Close #78 - Add Create Gitlab issue for newsletter too 2025-04-17 11:15:39 +02:00
Vincent BRIDIER
af1c739f72
feat: Close #62 - Add Edit btn on ticket show 2025-04-17 11:00:20 +02:00
Vincent BRIDIER
16dd015290
fix: Fix MEP date validation and UX 2025-04-17 10:53:19 +02:00
Vincent BRIDIER
8bb823512d
fix: Fix ticket sorting 2025-04-17 10:47:05 +02:00
Vincent BRIDIER
4de74c8f5f
feat: Remove useless dutyhours and home 2025-04-11 18:41:09 +02:00
Vincent BRIDIER
e06558d8c6
feat: Update Ticket UI/UX 2025-04-11 18:30:04 +02:00
Noah Lancien
ca7057ce77 Merge branch 'develop' into trunk 2025-04-08 14:11:31 +02:00
noah.lancien
99744045e9 Merge branch 'issue-77-linking' into 'develop'
feat: ✨ added the possibility of linking tickets !77

See merge request ldc-web/projets/support-web!96
2025-04-08 12:11:06 +00:00
Corentin Huet
d58f697ed8 feat: ✨ added the possibility of linking tickets 2025-04-08 14:09:22 +02:00
noah.lancien
61833abfc5 Merge branch 'issue-76-mep' into 'develop'
Issue 76 date mep

See merge request ldc-web/projets/support-web!95
2025-04-08 10:30:36 +00:00
Corentin Huet
f9c02af11b feat: ✨ added mep date on tickets 2025-04-08 12:25:35 +02:00
noah.lancien
3836cc50e8 Merge branch 'issue-75-priority' into 'develop'
feat: ✨ using order method for set a priority to a ticket

See merge request ldc-web/projets/support-web!94
2025-04-08 10:02:48 +00:00
Alexis Gousseau
f932818c45 feat: ✨ set priority on tickets with order functionnality #75 2025-04-08 11:57:15 +02:00
Vincent BRIDIER
763d8e9467 Merge branch 'issue-69' into 'develop'
fix: 🐛 login page is now only accessible for unauth users #69

See merge request ldc-web/projets/support-web!98
2025-04-08 09:03:43 +00:00
Alexis Gousseau
14051a908e fix: 🐛 login page is now only accessible for unauth users #69 2025-04-08 10:49:27 +02:00
Corentin Huet
64b95f6f28 feat: ✨ add order on tickets 2025-04-08 09:46:47 +02:00
Noah Lancien
0dd283b68d Merge branch 'trunk' 2025-04-07 15:01:11 +02:00
Noah Lancien
7c028a4505 Merge branch 'develop' into trunk 2025-04-07 15:00:52 +02:00
noah.lancien
397ed4272b Merge branch 'ticket-management' into 'develop'
feat: 🐛 replace sebastien by nicolas in GitlabUsersEnum

See merge request ldc-web/projets/support-web!97
2025-04-07 12:59:29 +00:00
Nicolas Demangeat
cef170adaa fix: 🐛 change the id in GitlabUsersEnum an remove unuse user 2025-04-07 14:55:09 +02:00
Nicolas Demangeat
1506891d21 feat: 🐛 replace sebastien by nicolas in GitlabUsersEnum 2025-04-07 14:44:20 +02:00
Vincent BRIDIER
8d6723f262
feat: Update README.md 2025-03-13 07:48:29 +01:00
Vincent BRIDIER
4367c35976
feat: Update README.md project name 2025-03-13 07:43:22 +01:00
Karl Muller
b21dd4d260 Merge branch 'trunk' 2025-03-07 14:27:01 +00:00
Karl Muller
4838b54b4c Merge branch 'develop' into trunk 2025-03-07 14:26:49 +00:00
Karl Muller
9b0f1e0241 fix: add php v on Dockerfile 2025-03-07 14:25:57 +00:00
Karl Muller
911ee5df4b Merge branch 'trunk' 2025-03-07 14:10:23 +00:00
Karl Muller
bbfd4360f2 Merge branch 'develop' into trunk 2025-03-07 14:09:58 +00:00
karl.muller
2786972b41 Merge branch 'chore/laravel11' into 'develop'
chore: 📦 bump in laravel 11 + robots.txt

See merge request ldc-web/projets/support-web!93
2025-03-07 14:09:05 +00:00
Karl Muller
a8605236a7 chore: 📦 bump in laravel 11 + robots.txt 2025-03-07 10:28:17 +00:00
Vincent BRIDIER
3a51ccb0f3
Merge branch 'trunk' 2025-03-04 09:58:05 +01:00
Vincent BRIDIER
1c3f20782b
Merge branch 'develop' into trunk 2025-03-04 09:57:56 +01:00
Vincent BRIDIER
25f31ff7b2 Update TaskTypeEnum.php 2025-03-04 08:56:58 +00:00
Noah Lancien
673494aeda Merge branch 'trunk' 2025-02-20 14:41:26 +01:00
Noah Lancien
1bd04e2e52 Merge branch 'develop' into trunk 2025-02-20 14:41:11 +01:00
noah.lancien
fa1d8db4b2 Merge branch 'issue-72' into 'develop'
feat: ✨ add recetteValidated to TicketStatusEnum

See merge request ldc-web/projets/support-web!92
2025-02-20 13:40:44 +00:00
Nicolas Demangeat
372fadb865 feat: ✨ add recetteValidated to TicketStatusEnum 2025-02-20 10:12:11 +01:00
Noah Lancien
aa17aab45f Merge branch 'trunk' 2025-02-14 13:42:22 +01:00
Noah Lancien
ec47d2610f Merge branch 'develop' into trunk 2025-02-14 13:42:08 +01:00
Noah Lancien
df9d8d69fa fix: updated type filter icon 2025-02-14 13:42:00 +01:00
Noah Lancien
560ef30cd8 Merge branch 'trunk' 2025-02-14 13:31:00 +01:00
Noah Lancien
b2908aac9f Merge branch 'develop' into trunk 2025-02-14 13:30:20 +01:00
noah.lancien
59415e1926 Merge branch 'issue-73-type-filter' into 'develop'
feat: Add type filter

See merge request ldc-web/projets/support-web!91
2025-02-14 12:29:39 +00:00
Noah Lancien
aaf114fa30 feat: Add type filter 2025-02-14 13:26:45 +01:00
Karl Muller
0da4a6fa13 Merge branch 'trunk' 2025-01-13 13:56:41 +00:00
Karl Muller
b6720bae3d Merge branch 'develop' into trunk 2025-01-13 13:46:09 +00:00
Karl Muller
a58bf2ff3b fix: change manifest for cron issue 2025-01-13 13:45:04 +00:00
Karl Muller
4c4a18ac70 fix: composer update to fix CVE 2025-01-13 13:44:22 +00:00
Noah Lancien
2b94d780b6 Merge branch 'trunk' 2024-11-26 09:18:29 +01:00
Noah Lancien
74edc5c785 Merge branch 'develop' into trunk 2024-11-26 09:17:42 +01:00
Noah Lancien
4de7a0c5ca fix: remove brackets for Invoice->tasks 2024-11-26 09:17:19 +01:00
Noah Lancien
781161c5e4 Merge branch 'trunk' 2024-11-25 17:19:55 +01:00
Noah Lancien
2d70ff9f29 Merge branch 'develop' into trunk 2024-11-25 17:18:41 +01:00
Noah Lancien
27258558a7 chore: composer update to fix some CVE 2024-11-25 17:18:25 +01:00
Noah Lancien
17a01e1f7a Merge branch 'trunk' 2024-11-25 17:12:45 +01:00
Karl Muller
e3d828a9e5 Merge branch 'develop' into trunk 2024-11-25 15:50:32 +00:00
karl.muller
9a1f23b85f Merge branch 'issue-70' into 'develop'
feat: 💄 improve invoice pdf

See merge request ldc-web/projets/support-web!90
2024-11-25 15:48:53 +00:00
Nicolas Demangeat
260e109ba1 feat: 💄 improve invoice pdf 2024-11-25 15:58:56 +01:00
Noah Lancien
d17678342e Merge branch 'trunk' 2024-11-12 14:32:29 +01:00
Noah Lancien
b646cb41fe Merge branch 'develop' into trunk 2024-11-12 14:07:35 +01:00
Noah Lancien
8f690473f8 chore: phpcs 2024-11-12 14:06:31 +01:00
noah.lancien
cc7a9b54e5 Merge branch 'issue-67' into 'develop'
Issue 67

See merge request ldc-web/projets/support-web!88
2024-11-12 13:02:58 +00:00
Noah Lancien
5e459a6571 fix: some elements crashed since the inscrease of files in tickets and messages 2024-11-12 12:52:21 +01:00
Vincent BRIDIER
2f80eb5853 Update README 2024-08-19 07:53:58 +00:00
Vincent BRIDIER
0ebdc9a984 Update README 2024-08-19 07:53:38 +00:00
Noah Lancien
5bd7673a18 Merge branch 'trunk' 2024-07-31 12:21:21 +02:00
Noah Lancien
2faf043f68 Merge branch 'develop' into trunk 2024-07-31 12:12:17 +02:00
noah.lancien
a44ee6f83c Merge branch 'issue-68' into 'develop'
fix: deleted user management for estimation

See merge request ldc-web/projets/support-web!89
2024-07-31 10:10:40 +00:00
Nicolas Demangeat
6ae38392ea fix: deleted user management for estimation 2024-07-31 12:02:15 +02:00
Nicolas Demangeat
c770d5d80e feat: you can set the amout by 0.5hours now, improve display in invoice show blade 2024-07-29 15:20:57 +02:00
Nicolas Demangeat
e7c1acf8a4 feat: can add 3 files for messages and 5 for tickets 2024-07-29 14:23:37 +02:00
Nicolas Demangeat
23e296978d wip: mimes type for ticket files 2024-07-29 08:47:28 +02:00
Vincent BRIDIER
66c889b02a
Merge branch 'trunk' 2024-07-26 15:33:24 +02:00
Vincent BRIDIER
74600ef3a7
Merge branch 'develop' into trunk 2024-07-26 15:06:54 +02:00
Vincent BRIDIER
889ee1e7f4
Update SP management for SAML 2024-07-26 15:06:30 +02:00
Vincent BRIDIER
738cfb7aea
PHPCS 2024-07-26 15:05:16 +02:00
Vincent BRIDIER
35e18112b9
Merge branch 'develop' into trunk 2024-07-25 17:29:35 +02:00
Vincent BRIDIER
b024dbd007
Fix SAML without CSP on login + idp pem loading 2024-07-25 17:29:19 +02:00
Nicolas Demangeat
a4d0b131a4 feat: wip, validation tickets and messages request 2024-07-23 13:44:51 +02:00
Nicolas Demangeat
c23e2289e5 feat: wip issue 67 2024-07-22 11:32:03 +02:00
Vincent BRIDIER
f10b46a012
Merge branch 'trunk' 2024-07-20 23:18:59 +02:00
Vincent BRIDIER
523715a3c1
Merge branch 'develop' into trunk 2024-07-20 23:01:04 +02:00
Vincent BRIDIER
2eacc46be0
Add SAML deps for IDP feature 2024-07-20 23:00:34 +02:00
Vincent BRIDIER
c8b4f97c88
Merge branch 'trunk' 2024-07-10 15:23:32 +02:00
Vincent BRIDIER
65b92edc99
Merge branch 'develop' into trunk 2024-07-10 15:23:17 +02:00
Vincent BRIDIER
0874e9202c Merge branch 'issue-64' into 'develop'
fix: InvoiceTasksComponent and invoice.blade

See merge request ldc-web/projets/support-web!87
2024-07-10 09:06:39 +00:00
nicolas.demangeat
ae68ce0f16 fix: InvoiceTasksComponent and invoice.blade
Close #64
2024-07-10 09:06:38 +00:00
Thibault Raquet
2ee245be4c Merge branch 'trunk' into 'master'
Trunk

See merge request ldc-web/projets/support-web!86
2024-06-27 08:58:58 +00:00
Thibault Raquet
766a990361 Merge branch 'develop' into 'trunk'
Develop

See merge request ldc-web/projets/support-web!85
2024-06-27 08:58:33 +00:00
Thibault Raquet
dc47b8d6e2 Merge branch 'prod-migration' into 'develop'
Prod migration

See merge request ldc-web/projets/support-web!84
2024-06-27 08:58:01 +00:00
Thibault Raquet
fad9d1207f Prod migration 2024-06-27 08:58:01 +00:00
Vincent BRIDIER
a23509fa09
Merge branch 'trunk' 2024-06-11 10:22:48 +02:00
Vincent BRIDIER
6c8cc25bae
Merge branch 'develop' into trunk 2024-06-11 10:07:26 +02:00
Vincent BRIDIER
af4509c7ca Merge branch 'fixed-invoices-new-lines' into 'develop'
Fix: Invoices new lines are now displayed

See merge request ldc-web/projets/support-web!83
2024-06-11 08:06:42 +00:00
Vincent BRIDIER
58280dd384 Merge branch 'invoice-search' into 'develop'
Invoice search

See merge request ldc-web/projets/support-web!81
2024-06-11 08:06:16 +00:00
Vincent BRIDIER
4da19cb742 Merge branch 'invoice-query-update' into 'develop'
add ->orderByDesc to the invoiceModels query in InvoiceController

See merge request ldc-web/projets/support-web!80
2024-06-11 08:04:56 +00:00
Vincent BRIDIER
0c34b4ebbf Merge branch 'add-estimation' into 'develop'
add account->balance in form-inputs for estimations

See merge request ldc-web/projets/support-web!79
2024-06-11 08:04:29 +00:00
Vincent BRIDIER
2eeb29d98b Merge branch 'modif-ticketStatusEnum' into 'develop'
change estimateTodo name in TicketStatusEnum

See merge request ldc-web/projets/support-web!78
2024-06-11 08:03:41 +00:00
nicolas.demangeat
b64dbf3eed change estimateTodo name in TicketStatusEnum 2024-06-11 08:03:40 +00:00
Noah Lancien
5128ba471b Fix: Invoices new lines are now displayed 2024-06-11 09:45:12 +02:00
Nicolas Demangeat
daad752be1 add site_id to invoices research in InvoiceController 2024-06-03 16:57:47 +02:00
Nicolas Demangeat
2f1976bf83 add ->orderByDesc to the invoiceModels query in InvoiceController 2024-06-03 16:43:27 +02:00
Nicolas Demangeat
4eda19604c add account->balance in form-inputs for estimations 2024-06-03 16:31:05 +02:00
Vincent BRIDIER
704551c165 Merge branch 'fix-ticket-show' into 'develop'
Fix ticket show

See merge request ldc-web/projets/support-web!77
2024-02-05 14:40:21 +00:00
nicolas.demangeat
08a92a1d97 Fix ticket show 2024-02-05 14:40:20 +00:00
Vincent BRIDIER
3c529a7bc0
Merge branch 'trunk' 2024-02-05 12:17:39 +01:00
Vincent BRIDIER
c8d179e7b3
Merge branch 'develop' into trunk 2024-02-05 12:09:45 +01:00
Vincent BRIDIER
af97d31fc3 Merge branch 'fix-ticket-show' into 'develop'
fix ticket show blade

See merge request ldc-web/projets/support-web!76
2024-02-05 11:09:10 +00:00
nicolas.demangeat
d3a01593a3 fix ticket show blade 2024-02-05 11:09:10 +00:00
Vincent BRIDIER
8e4d6d4198
Merge branch 'develop' into trunk 2024-02-02 11:34:37 +01:00
Vincent BRIDIER
434dd45a5d Merge branch 'add-ticket-title' into 'develop'
add field for the title of a ticket, make the migration and the request

See merge request ldc-web/projets/support-web!72
2024-02-02 10:34:06 +00:00
nicolas.demangeat
9675c1bb3a add field for the title of a ticket, make the migration and the request 2024-02-02 10:34:06 +00:00
Vincent BRIDIER
4cd2980227 Merge branch 'issue-56' into 'develop'
change class attribut to text-bg-dark in tickets show blade line 179

See merge request ldc-web/projets/support-web!75
2024-02-01 08:42:56 +00:00
Nicolas Demangeat
67a364afe8 change class attribut to text-bg-dark in tickets show blade line 179 2024-02-01 09:41:30 +01:00
Vincent BRIDIER
a3c2697c86
Merge branch 'trunk' 2024-01-31 18:03:13 +01:00
Vincent BRIDIER
c6d89101b4
Merge branch 'develop' into trunk 2024-01-31 17:55:33 +01:00
Vincent BRIDIER
e17a415fad Merge branch '50-invoices-search-ref' into 'develop'
update searchfield for invoices

See merge request ldc-web/projets/support-web!74
2024-01-31 16:54:39 +00:00
Vincent BRIDIER
6a53d7ec45 Merge branch '53-devis-changement-de-restrictions-sur-les-montants-des-lignes' into 'develop'
update invoices request

See merge request ldc-web/projets/support-web!73
2024-01-31 16:52:10 +00:00
Vincent BRIDIER
8687adfa30 Merge branch '52-devis-saisie-de-commentaires' into 'develop'
remove condition in invoices form-inputs

See merge request ldc-web/projets/support-web!71
2024-01-31 16:44:28 +00:00
Vincent BRIDIER
b762dfc053 Update manifest 2023-12-11 11:13:53 +00:00
Nicolas Demangeat
8a3e175cd0 update searchfield for invoices 2023-11-14 09:45:16 +01:00
Nicolas Demangeat
ab43676c0a update invoices request 2023-11-14 09:37:49 +01:00
Nicolas Demangeat
c192991470 remove condition in invoices form-inputs 2023-11-13 14:31:12 +01:00
Vincent BRIDIER
ad43378b52
Merge branch 'trunk' 2023-10-13 15:23:19 +02:00
Vincent BRIDIER
f40f2e2aa5
Merge branch 'develop' into trunk 2023-10-13 15:16:29 +02:00
Vincent BRIDIER
b301e53c34 Fix #49 2023-10-13 13:15:10 +00:00
Vincent BRIDIER
75d03386f3 Merge branch 'issue-48' into 'develop'
Issue 48

See merge request ldc-web/projets/support-web!70
2023-10-13 13:14:19 +00:00
Jérémy Munsch
3126bd9e92
Fixes #48 invoice comment was not printed in html 2023-10-13 10:56:20 +02:00
Jérémy Munsch
1b1cb44650
composer update 2023-10-13 10:47:58 +02:00
Vincent BRIDIER
b55d812aaa Merge branch 'develop' into trunk 2023-10-12 16:55:19 +02:00
Vincent BRIDIER
8c19bc9785 Merge branch 'issue-45' into 'develop'
Closes #45 Allow update comment on invoice

See merge request ldc-web/projets/support-web!69
2023-10-12 14:54:46 +00:00
Vincent BRIDIER
74bdeb7383 Merge branch 'issue-47' into 'develop'
Issue 47

See merge request ldc-web/projets/support-web!68
2023-10-12 14:52:23 +00:00
Jérémy Munsch
e3fddc1593
Closes #45 Allow update comment on invoice 2023-10-12 16:30:43 +02:00
Jérémy Munsch
8ba7fc3714
Closes #47 Readd Softdelete on Site 2023-10-12 16:13:54 +02:00
Jérémy Munsch
fa230c3559
Fix composer name, version and description 2023-10-12 15:56:46 +02:00
Jérémy Munsch
b3caca9f74
Front bump using base project 2023-10-12 15:56:11 +02:00
Jérémy Munsch
fa97a5e822
ckeditor update 2023-10-12 15:27:42 +02:00
Jérémy Munsch
b0e3eab3f7
lang update 2023-10-12 15:22:31 +02:00
Jérémy Munsch
f06df43cfe
composer update 2023-10-12 15:22:05 +02:00
Vincent BRIDIER
ab08bad87e Merge branch 'trunk' 2023-10-12 11:47:11 +02:00
Vincent BRIDIER
e8b920a8cd Merge branch 'develop' into trunk 2023-10-12 11:18:37 +02:00
Vincent BRIDIER
4cbce831a0 Merge branch '46-pouvoir-renseigner-des-donnees-de-site-sans-id-du-depot-gitlab' into 'develop'
change required to false for gitlab project id

See merge request ldc-web/projets/support-web!67
2023-10-12 09:14:12 +00:00
Vincent BRIDIER
09356e6ee4 Merge branch 'issue-42' into 'develop'
Send mail to new users

See merge request ldc-web/projets/support-web!65
2023-10-12 09:12:36 +00:00
Nicolas Demangeat
4ad9c0e39f change required to false for gitlab project id 2023-10-12 10:59:58 +02:00
Vincent BRIDIER
cb779c83b8
Merge branch 'trunk' 2023-10-09 15:09:26 +02:00
Vincent BRIDIER
a393b24392
Merge branch 'develop' into trunk 2023-10-04 11:38:28 +02:00
Vincent BRIDIER
905304e1ea Merge branch '44-amelioration-liste-des-devis' into 'develop'
add sent accounting date to invoces index

See merge request ldc-web/projets/support-web!66
2023-10-04 09:35:12 +00:00
Nicolas Demangeat
2068b7fd72 add sent accounting date to invoces index 2023-10-04 11:11:20 +02:00
Noah Lancien
f5a3353d09 Confirm mail is now send to every newly created user 2023-09-25 17:35:14 +02:00
Vincent BRIDIER
cd89f6b443 Merge branch 'trunk' 2023-08-24 16:21:39 +02:00
Vincent BRIDIER
d9b316eae4 Merge branch 'develop' into trunk 2023-08-24 16:01:54 +02:00
Vincent BRIDIER
13c1c304d3 Merge branch '41-ticket-index-reset-filter' into 'develop'
fix reset filter

See merge request ldc-web/projets/support-web!64
2023-08-24 14:00:10 +00:00
nicolas.demangeat
40a8703667 fix reset filter 2023-08-24 14:00:10 +00:00
Vincent BRIDIER
722369cf61 Merge branch 'develop' into trunk 2023-08-24 12:37:14 +02:00
Vincent BRIDIER
d90f9f03c5 Merge branch '41-ticket-index-reset-filter' into 'develop'
remove ticket search when reset filter

See merge request ldc-web/projets/support-web!63
2023-08-24 10:35:56 +00:00
Vincent BRIDIER
0cc315d2ef Merge branch 'develop' into trunk 2023-08-24 12:35:08 +02:00
Nicolas Demangeat
4033fe8863 remove ticket search when reset filter 2023-08-24 12:34:41 +02:00
Vincent BRIDIER
759c474272 Merge branch '40-csp-save-clone-btn' into 'develop'
Resolve "CSP Save clone btn"

See merge request ldc-web/projets/support-web!62
2023-08-24 10:17:53 +00:00
Nicolas Demangeat
036d7109c7 add nonce to script 2023-08-24 12:09:05 +02:00
Vincent BRIDIER
7559a47044
Merge branch 'trunk' 2023-08-18 12:37:30 +02:00
Vincent BRIDIER
55fef3421e
Merge branch 'develop' into trunk 2023-08-18 12:37:14 +02:00
Vincent BRIDIER
ef897b17b2 Merge branch 'issue-39' into 'develop'
remove schedule/stats functionnalities - issue #39

See merge request ldc-web/projets/support-web!61
2023-08-18 10:36:00 +00:00
Vincent BRIDIER
d95f413bbb Merge branch 'issue-37' into 'develop'
Issue 37

See merge request ldc-web/projets/support-web!60
2023-08-18 10:27:09 +00:00
Alexis Gousseau
58d9c9e498 remove schedule/stats functionnalities - issue #39 2023-08-18 09:32:13 +02:00
Vincent BRIDIER
39f6001472 add test mail command 2023-08-18 06:43:17 +00:00
Noah Lancien
24f7c1f73a Removed status from projects 2023-08-17 16:53:01 +02:00
Noah Lancien
c16871abb0 Fixed missing validations, some wording, SearchBelongsToDropdownComponent old values 2023-08-17 16:52:17 +02:00
Vincent BRIDIER
0d20b9726c Merge branch 'issue-38' into 'develop'
Change Datetime to Date

See merge request ldc-web/projets/support-web!59
2023-08-17 13:15:55 +00:00
Sebastien Hattry
4e8a1ab987 Change Datetime to Date 2023-08-17 12:43:22 +00:00
Vincent BRIDIER
97d8111f4b
Merge branch 'trunk' 2023-08-17 11:21:13 +02:00
Vincent BRIDIER
4354f6a445
Merge branch 'develop' into trunk 2023-08-17 11:18:26 +02:00
Vincent BRIDIER
abac13755f
Update manifest 2023-08-17 11:18:08 +02:00
Vincent BRIDIER
abdbbae843
Merge branch 'develop' into trunk 2023-08-16 12:24:45 +02:00
Vincent BRIDIER
0633d6ebef
fix policy ticket gitlab 2023-08-16 12:24:32 +02:00
Vincent BRIDIER
8f37b29cee Merge branch 'issue-36' into 'develop'
Page liste de mes sites avec urls

See merge request ldc-web/projets/support-web!58
2023-08-16 10:23:50 +00:00
noah.lancien
632f9a90f1 Issue #36 - Page liste de mes sites avec urls 2023-08-16 10:23:50 +00:00
Vincent BRIDIER
f150e96d39
Merge branch 'develop' into trunk 2023-08-16 10:30:48 +02:00
Vincent BRIDIER
c8f8784c68 Merge branch 'issue-17' into 'develop'
Issue 17 - Creation d'issue à partie d'un ticket SW

See merge request ldc-web/projets/support-web!57
2023-08-16 08:28:59 +00:00
noah.lancien
5b837f907d Issue 17 - Creation d'issue à partie d'un ticket SW 2023-08-16 08:28:59 +00:00
Vincent BRIDIER
c155e48d78 Merge branch 'issue-19' into 'develop'
add status on invoices - issue #19

See merge request ldc-web/projets/support-web!53
2023-08-14 17:48:26 +00:00
Alexis Gousseau
4f7f12de59 add status on invoices - issue #19 2023-08-14 17:48:26 +00:00
Vincent BRIDIER
8dac597561 Merge branch 'fix-sites-update' into 'develop'
Used sync instead of detach/attach for sites and users update

See merge request ldc-web/projets/support-web!56
2023-08-14 14:16:56 +00:00
Vincent BRIDIER
773a4b6cb2 Merge branch 'issue-23' into 'develop'
add last_activity field on ticket - issue #23

See merge request ldc-web/projets/support-web!55
2023-08-14 14:15:14 +00:00
Alexis Gousseau
53eff1b7a2 add last_activity field on ticket - issue #23 2023-08-14 14:15:13 +00:00
Noah Lancien
2c9540c283 Used sync instead of detach/attach for sites and users update 2023-08-14 16:06:55 +02:00
Vincent BRIDIER
877ad8566f Merge branch 'issue-35' into 'develop'
fix button archived tickets - issue #35

See merge request ldc-web/projets/support-web!54
2023-08-14 13:48:52 +00:00
Alexis Gousseau
a78dcc54a1 fix button archived tickets - issue #35 2023-08-14 14:24:51 +02:00
Vincent BRIDIER
d2324145a4
Merge branch 'develop' into trunk 2023-08-14 11:24:22 +02:00
Vincent BRIDIER
769a04d6bf Merge branch 'bump-laravel-10' into 'develop'
Bump laravel 10

See merge request ldc-web/projets/support-web!52
2023-08-14 09:23:39 +00:00
Alexis Gousseau
8bf48697f4 Bump Laravel 10 + Fixes + Improvements ISO scope 2023-08-14 09:23:39 +00:00
Vincent BRIDIER
d6d3bba81c Merge branch '30-auto-validate-estimate' into 'develop'
Resolve "Auto Validate Estimate"

See merge request ldc-web/projets/support-web!30
2023-08-03 08:21:06 +00:00
Nicolas Demangeat
7698a5c7ec add dev policy to validate ou reject an estimation 2023-07-31 12:32:11 +02:00
Vincent BRIDIER
b6c74efd3d
Merge branch 'trunk' 2023-07-20 15:31:37 +02:00
Vincent BRIDIER
57a437db48
Merge branch 'develop' into trunk 2023-07-20 15:31:24 +02:00
Vincent BRIDIER
24ff4fdec5 Merge branch '20-archived-tickets-missing-private-messages' into 'develop'
Resolve "Archived Tickets - missing private messages"

Closes #20

See merge request ldc-web/projets/support-web!29
2023-07-20 13:31:02 +00:00
Nicolas Demangeat
26eb53a682 update TicketPolicy 2023-07-20 14:57:34 +02:00
Vincent BRIDIER
f3cb8e7974
Merge branch 'trunk' 2023-06-30 09:14:08 +02:00
Vincent BRIDIER
91c1fe5532
Merge branch 'develop' into trunk 2023-06-30 09:13:52 +02:00
Vincent BRIDIER
36623972ac Merge branch '16-reopen-ticket-error-500' into 'develop'
Resolve "ReOpen ticket error 500"

Closes #16

See merge request ldc-web/projets/support-web!28
2023-06-30 07:13:21 +00:00
Nicolas Demangeat
36aaf37be1 change call method in reopen function 2023-06-30 07:10:13 +00:00
Vincent BRIDIER
29a837ff61
Merge branch 'trunk' 2023-06-29 10:12:31 +02:00
Vincent BRIDIER
bbe4478c09
Merge branch 'develop' into trunk 2023-06-29 10:12:14 +02:00
Vincent BRIDIER
6229cf7518 Merge branch '15-parse-error-jobs-autocloseoldtickets-php' into 'develop'
Resolve "Parse Error Jobs/AutoCloseOldTickets.php"

Closes #15

See merge request ldc-web/projets/support-web!27
2023-06-29 08:11:01 +00:00
nicolas.demangeat
9603a6e30c Resolve "Parse Error Jobs/AutoCloseOldTickets.php" 2023-06-29 08:11:01 +00:00
Vincent BRIDIER
07da333c37 Merge branch 'refecto' into 'develop'
refactor ScheduleController

See merge request ldc-web/projets/support-web!26
2023-06-26 07:16:45 +00:00
Nicolas Demangeat
97c01c5962 refactor ScheduleController 2023-06-23 07:14:39 +00:00
Vincent BRIDIER
28ee9f593d
Merge branch 'trunk' 2023-06-22 14:58:09 +02:00
Vincent BRIDIER
eb2d4e5267
Merge branch 'develop' into trunk 2023-06-22 14:57:42 +02:00
Vincent BRIDIER
292d62af3f Merge branch '14-vue-planning' into 'develop'
Resolve "Vue planning"

Closes #14

See merge request ldc-web/projets/support-web!25
2023-06-22 12:56:02 +00:00
Nicolas Demangeat
a6ffc740e3 add feature to filter auth user schedule and refactor controller 2023-06-22 11:08:17 +00:00
Vincent BRIDIER
c19d5829e6
Merge branch 'trunk' 2023-04-25 11:35:01 +02:00
Vincent BRIDIER
c1fb743e34
Merge branch 'develop' into trunk 2023-04-25 11:34:24 +02:00
Vincent BRIDIER
5ec3230c40
Update composer json 2023-04-25 11:34:01 +02:00
Vincent BRIDIER
d4327903b3 Merge branch 'issue-13' into 'develop'
Fix #13

Closes #13

See merge request ldc-web/projets/support-web!24
2023-04-25 09:30:25 +00:00
Jérémy Munsch
9fff1f4c8a Fix #13 2023-04-25 09:30:25 +00:00
Vincent BRIDIER
3bbe160e20 Merge branch 'issue-12' into 'develop'
Fix #12

Closes #12

See merge request ldc-web/projets/support-web!23
2023-04-25 09:24:47 +00:00
Jérémy Munsch
e8d0ab76f1 Fix #12 2023-04-25 09:24:47 +00:00
Vincent BRIDIER
bf43eb7a3d Merge branch 'issue-11' into 'develop'
Close #11

Closes #11

See merge request ldc-web/projets/support-web!22
2023-04-25 09:17:47 +00:00
Jérémy Munsch
9891b08815 Close #11 2023-04-25 09:17:47 +00:00
Vincent BRIDIER
1d07c93799
Merge branch 'trunk' 2023-04-18 17:27:35 +02:00
Vincent BRIDIER
32cb11622c
Merge branch 'develop' into trunk 2023-04-18 17:27:21 +02:00
Vincent BRIDIER
bd7d44c1db
merge develop 2023-04-18 17:12:39 +02:00
Vincent BRIDIER
a75254568b
remove ldcweb name 2023-04-18 17:11:22 +02:00
Vincent BRIDIER
ad71a8439d
disalow index by bots 2023-04-18 17:11:07 +02:00
Vincent BRIDIER
d0ef0ac2af
update ideas 2023-04-18 17:10:52 +02:00
Vincent BRIDIER
63d243acc3
Bump + update changelog 2023-04-18 17:10:39 +02:00
Vincent BRIDIER
4e67acf98b Merge branch 'issue-9' into 'develop'
Issue 9 - Message Info

Closes #9

See merge request ldc-web/projets/support-web!20
2023-04-18 14:57:59 +00:00
noah.lancien
af408f4e61 Issue 9 - Message Info 2023-04-18 14:57:59 +00:00
noah.lancien
1e916d9701 Move compiled files from public to public/build 2023-04-18 14:45:07 +00:00
Vincent BRIDIER
d04f8aeeab Merge branch 'duty-hours' into 'develop'
Duty hours

See merge request ldc-web/projets/support-web!19
2023-04-18 14:28:20 +00:00
Vincent BRIDIER
e3a202b0c6
Clean duty hours request 2023-04-18 16:27:19 +02:00
noah.lancien
e8836e4789 Added information model to display info on pages 2023-04-18 13:57:34 +00:00
noah.lancien
3ba7a19cc4 Made duty hours display more simple 2023-04-18 12:48:55 +00:00
noah.lancien
fa810ad17f Added duty hours display on homepage 2023-04-18 12:39:40 +00:00
noah.lancien
8678ce520b Added validation rules for duty hours 2023-04-18 12:32:46 +00:00
noah.lancien
d49bb5eaa7 Added CRUD for Duty Hours 2023-04-18 10:46:40 +00:00
Vincent BRIDIER
911d7a2f6d
Merge branch 'trunk' 2023-04-17 17:21:58 +02:00
Vincent BRIDIER
32be1746b5
Merge branch 'develop' into trunk 2023-04-17 16:22:06 +02:00
Vincent BRIDIER
4ab70133d4 Merge branch 'issue-3' into 'develop'
Fixed : system message when assignment kept message for status changes

Closes #3

See merge request ldc-web/projets/support-web!18
2023-04-17 14:16:12 +00:00
noah.lancien
64e8feea1e Fixed boolean for status changes event 2023-04-17 13:35:33 +00:00
noah.lancien
adfd7afed2 Fixed : system message when assignment kept message for status changes 2023-04-17 10:54:26 +00:00
Vincent BRIDIER
a5d4c58604
Merge branch 'develop' into trunk 2023-04-12 15:47:13 +02:00
Vincent BRIDIER
72268bd285 Merge branch 'issue-6' into 'develop'
Issue 6

Closes #6

See merge request ldc-web/projets/support-web!17
2023-04-12 10:20:07 +00:00
noah.lancien
d89ad43426 fixed some phpcs warnings 2023-04-12 10:18:21 +00:00
noah.lancien
00bacab688 Fixed message type when a ticket is assigned 2023-04-12 10:14:18 +00:00
noah.lancien
c51e27445d Fixed message display for system messages 2023-04-12 10:12:46 +00:00
noah.lancien
46e3018f0d Merge branch 'develop' into issue-6 2023-04-12 09:44:04 +00:00
Vincent BRIDIER
a37e0276e4 Merge branch 'issue-5' into 'develop'
Issue 5

Closes #5

See merge request ldc-web/projets/support-web!16
2023-04-12 09:40:01 +00:00
noah.lancien
9742e805d0 Issue 5 2023-04-12 09:40:01 +00:00
noah.lancien
c6b62cd2c5 Merge branch 'issue-5' into issue-6 2023-04-12 07:20:05 +00:00
noah.lancien
19a209c06b Fixed migration to add the type column to the messages table 2023-04-12 07:11:28 +00:00
noah.lancien
32de7a50ab Merge branch 'develop' into issue-5 2023-04-12 07:01:36 +00:00
Vincent BRIDIER
b57c9e9510 Merge branch 'issue-7' into 'develop'
Added ActivityType/CellType LeadDev

Closes #7

See merge request ldc-web/projets/support-web!15
2023-04-11 15:36:35 +00:00
Vincent BRIDIER
4f3da31750 Merge branch 'issue-4' into 'develop'
Added qrcode and advice types

Closes #4

See merge request ldc-web/projets/support-web!14
2023-04-11 15:36:19 +00:00
Vincent BRIDIER
3546730e60 Merge branch 'issue-3' into 'develop'
Added more text in system messages

Closes #3

See merge request ldc-web/projets/support-web!13
2023-04-11 15:35:54 +00:00
noah.lancien
8e0a51e3e6 Cleaned sprintf 2023-04-11 15:33:58 +00:00
noah.lancien
a13124f2c6 Used sprintf() and __() in texts 2023-04-11 15:22:29 +00:00
Vincent BRIDIER
1a3f3d57ce Merge branch 'issue-2' into 'develop'
Issue 2

Closes #2

See merge request ldc-web/projets/support-web!12
2023-04-11 15:15:31 +00:00
noah.lancien
16b2016c0e Fixed status when creating a ticket 2023-04-11 15:05:29 +00:00
noah.lancien
1c361f504c Added reverse migration 2023-04-11 15:03:24 +00:00
noah.lancien
9a49686f93 Cleand migration and updated with new enums 2023-04-11 12:28:33 +00:00
noah.lancien
aa381ac61b Re-ordered ticket status enums 2023-04-11 12:28:00 +00:00
noah.lancien
72d16e5f0c Made border larger to see it better with dark background 2023-04-06 14:23:36 +00:00
noah.lancien
b73563b258 Changed system message status to private when assign to a user 2023-04-06 14:05:32 +00:00
noah.lancien
4fd9c2f177 Fixed : system message is now public when status or assignment is updated 2023-04-06 14:00:30 +00:00
noah.lancien
467ebae681 Fixed migration to set all existing messages to public 2023-04-06 13:59:20 +00:00
noah.lancien
fb570b166b Added style and icon for private messages 2023-04-06 13:34:41 +00:00
noah.lancien
a631506cf1 Changed blade and request to create private or public messages 2023-04-06 13:26:20 +00:00
noah.lancien
1aab655964 Added migration to create 'type' column for messages 2023-04-06 13:25:37 +00:00
noah.lancien
5fa24d69c8 Added new policy to create private message 2023-04-06 13:24:40 +00:00
noah.lancien
0be5816bf7 Added cast to message model for type enum 2023-04-06 12:53:13 +00:00
noah.lancien
fada6d80e1 Created MessageType Enum 2023-04-06 10:20:30 +00:00
noah.lancien
c8ec9c8482 Added ActivityType/CellType LeadDev 2023-04-06 10:14:59 +00:00
noah.lancien
141122553e Added qrcode and advice types 2023-04-06 10:07:03 +00:00
noah.lancien
5d43c2d42e Added more text in system messages 2023-04-06 09:55:47 +00:00
noah.lancien
c1d5cb1dfc Fixed deleted enums used in Controller 2023-04-06 09:09:13 +00:00
noah.lancien
90d3a6f8e6 Created migration to change actual status 2023-04-06 08:56:20 +00:00
noah.lancien
4d37a18bae Updated ticket status when answer estimation is submitted 2023-04-06 08:55:49 +00:00
noah.lancien
78c80b9b38 Updated ticket status when created 2023-04-06 08:55:01 +00:00
noah.lancien
a5d20daab3 Updated Enums 2023-04-06 08:54:23 +00:00
Vincent BRIDIER
5fc956f45e Merge branch 'issue-1' into 'develop'
Issue 1

Closes #1

See merge request ldc-web/projets/support-web!11
2023-04-06 08:20:19 +00:00
noah.lancien
2dce9e4ad6 Updated composer.json 2023-04-06 08:18:46 +00:00
noah.lancien
3c4773bc63 Change button into link 2023-04-06 08:17:48 +00:00
noah.lancien
50fe558ba3 Removed parsedown package 2023-04-06 08:17:10 +00:00
noah.lancien
8672900cff Changed homepage elements 2023-04-06 07:41:20 +00:00
noah.lancien
cfd345f739 Move "/" route to middleware auth:web 2023-04-06 07:40:08 +00:00
noah.lancien
fbff1a4854 Changed gitlab domain for ldc packages 2023-04-06 07:31:25 +00:00
Vincent BRIDIER
13183e6aad add issue templates 2023-04-04 10:02:51 +00:00
Vincent BRIDIER
ad4b603a69
Update web dev price 2023-03-01 09:41:11 +01:00
Vincent BRIDIER
0d6f34b05a
Merge branch 'trunk' 2022-12-15 09:10:57 +01:00
Vincent BRIDIER
606ca09608
Merge branch 'develop' into trunk 2022-12-15 09:10:38 +01:00
Vincent BRIDIER
9d4868471a
Add Sentry 2022-12-15 09:10:17 +01:00
Vincent BRIDIER
803c457d27 Merge branch 'ticket1142' into 'develop'
Ticket1142

See merge request service-web-lab/support-web!10
2022-12-06 12:05:52 +00:00
Jérémy Munsch
515cb6505b
Ticket 1142 fix previous button on Planning 2022-12-01 16:40:42 +01:00
Jérémy Munsch
bf93f7ef92
Fix vue-select import with npm bump 2022-12-01 16:23:18 +01:00
Jérémy Munsch
63f5d5a4a0
npm update and composer update 2022-12-01 16:12:08 +01:00
Jérémy Munsch
6523875860
Merge branch 'trunk' 2022-11-04 17:04:58 +01:00
Jérémy Munsch
83b7e42b90
Merge branch 'develop' into trunk 2022-11-04 17:03:49 +01:00
Olivier Legat
a37e5686f5 Merge branch 'ticket1104' into 'develop'
fetch current user to assign letter in invoice ref

See merge request service-web-lab/support-web!9
2022-10-14 09:20:19 +00:00
Olivier Legat
99f61ac785
fetch current user to assign letter in invoice ref 2022-10-13 10:32:43 +02:00
Jérémy Munsch
6f20a6b8db
Merge branch 'develop' into trunk 2022-10-13 10:15:36 +02:00
Olivier Legat
6e7f2c559c Merge branch 'ticket1075' into 'develop'
fix url to paginated sites and projects

See merge request service-web-lab/support-web!8
2022-10-13 07:54:56 +00:00
Olivier Legat
e7118f7b3f
fix url to paginated sites and projects 2022-10-12 17:48:01 +02:00
Jérémy Munsch
88f3da4c92
Merge branch 'hotfix' 2022-10-12 14:22:46 +02:00
Jérémy Munsch
a2f52ac27d
Merge branch 'hotfix' into develop 2022-10-12 14:22:21 +02:00
Jérémy Munsch
96f2c98925
bump version 1.2.3 2022-10-12 14:21:36 +02:00
Jérémy Munsch
e577eef324
Ticket 1112: StoreTicket Labels presence check validation preventing regular user from creating tickets 2022-10-12 14:19:37 +02:00
Vincent BRIDIER
bd3133f06c
Merge branch 'trunk' 2022-10-11 12:06:30 +02:00
Vincent BRIDIER
bb2cbc5ad8
Merge branch 'develop' into trunk 2022-10-11 12:06:06 +02:00
Vincent BRIDIER
68a83e0e53 Merge branch 'ticket975' into 'develop'
Ticket 975 Upgrade HtmlSanitizer, Add missing middleware parameters on ...

See merge request service-web-lab/support-web!7
2022-10-04 09:20:40 +00:00
Vincent BRIDIER
d04678eb86 Merge branch 'ticket1076' into 'develop'
Ticket 1076 : Fix ticket Sync labels

See merge request service-web-lab/support-web!6
2022-10-04 09:07:15 +00:00
Jérémy Munsch
0b99ed5309
Ticket 975 Upgrade HtmlSanitizer, Add missing middleware parameters on sites.logs and projects.log resources routes 2022-09-29 14:39:20 +02:00
Jérémy Munsch
fd049309f3
Ticket 1076 : Fix ticket Sync labels 2022-09-29 13:02:18 +02:00
Jérémy Munsch
0f3fc52866
Merge branch 'hotfix' into develop 2022-09-05 09:05:34 +02:00
Jérémy Munsch
0414224156
Merge branch 'hotfix' 2022-09-05 09:05:27 +02:00
Jérémy Munsch
8964531818
Fix invoice download return type issue 2022-09-05 09:05:09 +02:00
Jérémy Munsch
0c4a8e64f2
Merge branch 'trunk' 2022-08-31 12:49:05 +02:00
Jérémy Munsch
03a0957404
Merge branch 'develop' into trunk 2022-08-31 12:48:54 +02:00
Vincent BRIDIER
e0d4d182ef Merge branch 'ticket1051' into 'develop'
Label select component Fixed label colors

See merge request service-web-lab/support-web!5
2022-08-31 10:47:55 +00:00
Jérémy Munsch
6f9cec1b2d
Label select component Fixed label colors 2022-08-31 12:44:18 +02:00
Vincent BRIDIER
c33ab9a416 Merge branch 'fixPaginationPlanningVueSelect' into 'develop'
Fix pagination planning vue select

See merge request service-web-lab/support-web!4
2022-08-31 10:34:00 +00:00
Jérémy Munsch
b687509abd
Schedule component Fix null message on new Modal cell 2022-08-31 12:30:39 +02:00
Vincent BRIDIER
0298fd82d2 Merge branch 'addMissingInvoiceMonthOnCreate' into 'develop'
Add missing invoice month on create

See merge request service-web-lab/support-web!3
2022-08-31 10:28:14 +00:00
Jérémy Munsch
c96b433d69
Fix pagination On Schedule 2022-08-31 12:23:47 +02:00
Jérémy Munsch
74801fad1b
Model Invoice : Add missing month on create 2022-08-31 12:06:30 +02:00
Jérémy Munsch
3045a809b3
add missing LDC_STATUS_CHECKER_API_KEY in .env.example 2022-08-30 18:03:55 +02:00
Jérémy Munsch
457a310d50
Merge branch 'trunk' 2022-08-30 17:32:05 +02:00
Jérémy Munsch
43f7376e0b
Merge branch 'develop' into trunk 2022-08-30 17:31:42 +02:00
Vincent BRIDIER
5d64a39268 Merge branch 'evolFactu' into 'develop'
Evol factu

See merge request service-web-lab/support-web!2
2022-08-30 13:21:08 +00:00
Jérémy Munsch
92a2834fca Évolution devis 2022-08-30 13:21:07 +00:00
Vincent BRIDIER
aa15694c0b Merge branch 'evolPlanningForceObject' into 'develop'
Evol planning force object

See merge request service-web-lab/support-web!1
2022-08-30 06:41:39 +00:00
Jérémy Munsch
7fe50bc847 Evol planning force object 2022-08-30 06:41:39 +00:00
Vincent BRIDIER
e167425f01
Handle user soft delete on planning 2022-08-22 15:38:36 +02:00
Jérémy Munsch
8d8b44fe13
Merge branch 'hotfix' into develop 2022-07-20 12:41:47 +02:00
Jérémy Munsch
2111aca9bc
Merge branch 'hotfix' 2022-07-20 12:41:42 +02:00
Jérémy Munsch
be746784f3
Change message Incident handled 2022-07-20 12:41:35 +02:00
Jérémy Munsch
68f2d45177
Merge branch 'hotfix' into develop 2022-07-20 12:24:21 +02:00
Jérémy Munsch
b910f6824d
Merge branch 'hotfix' 2022-07-20 11:19:11 +02:00
Jérémy Munsch
9817b0f7ca
overhal incident message 2022-07-20 11:18:57 +02:00
Jérémy Munsch
0789c74f76
Merge branch 'hotfix' 2022-07-20 11:09:56 +02:00
Jérémy Munsch
d0cf2278b9
Message incident 19/07/2022 2022-07-20 11:09:04 +02:00
Olivier Legat
bbb1b0517c Merge branch 'trunk' 2022-07-12 11:26:54 +02:00
Jérémy Munsch
6ac4e7602f
Merge branch 'develop' into trunk 2022-07-01 11:42:31 +02:00
Jérémy Munsch
fca641705a
bump to 1.2.2 + update changelog 2022-07-01 11:42:25 +02:00
Jérémy Munsch
a8f3dc2b50
Merge branch 'develop' into trunk 2022-07-01 11:31:46 +02:00
Jérémy Munsch
dcbbd49e36
Ticket n° 942 : fix ticket create label 2022-07-01 11:31:31 +02:00
Jérémy Munsch
9fac59ab19
Merge branch 'develop' into trunk 2022-07-01 11:26:16 +02:00
Jérémy Munsch
41d811a24e
Merge branch 'chromefixes' into develop 2022-07-01 11:25:58 +02:00
Jérémy Munsch
3971b4b2fc
Merge branch 'ticket962' into chromefixes
+ Add credit log check client has brands
2022-07-01 11:12:02 +02:00
Jérémy Munsch
97b492b87c
Ticket n° 928 Definitely fix 2022-07-01 11:05:15 +02:00
Jérémy Munsch
259ad1ba18
Ticket n° 957 Fix ticket wording archived condition 2022-07-01 09:27:36 +02:00
Jérémy Munsch
868f4a9dfb
Ticket n° 962 Fix unhandled case user is not admin on accounts 2022-06-30 17:51:15 +02:00
Olivier Legat
5602c0f66b Merge branch 'trunk' 2022-06-27 11:49:27 +02:00
Vincent BRIDIER
77d239f2f0
Merge branch 'develop' into trunk 2022-06-20 14:03:36 +02:00
Jérémy Munsch
64811b9eda
Fix Files.index path 2022-06-20 13:55:47 +02:00
Jérémy Munsch
8dd9aba195
Merge branch 'develop' into trunk 2022-06-17 14:25:27 +02:00
Jérémy Munsch
16dcb72800
Fix composer.lock unmerged 2022-06-17 14:24:34 +02:00
Jérémy Munsch
dc57df9ad0
Merge branch 'hotfix' 2022-06-17 09:38:16 +02:00
Jérémy Munsch
9bc9f8007a
Hotfix create ticket 2022-06-17 09:38:00 +02:00
Jérémy Munsch
6f6077281d
Merge branch 'hotfix' 2022-06-17 09:29:42 +02:00
Jérémy Munsch
da27907625
Add missing models name into trans 2022-06-17 09:29:29 +02:00
Vincent BRIDIER
8c94f580a9
Merge remote-tracking branch 'origin/ticket925' into develop 2022-06-16 12:07:38 +02:00
Vincent BRIDIER
b0081e82e6
merge ticket928 2022-06-16 12:06:03 +02:00
Vincent BRIDIER
56aa2b2a2c
Merge remote-tracking branch 'origin/ticket930' into develop 2022-06-16 12:02:50 +02:00
Vincent BRIDIER
1f8199b230
Merge remote-tracking branch 'origin/ticket933' into develop 2022-06-16 12:01:23 +02:00
Jérémy Munsch
296ebc62fe
add ticket link on credit logs 2022-06-15 18:52:24 +02:00
Jérémy Munsch
ba87af1327
Ticket 928
- add related model in accounts.index and creadit_logs.index
- Filter only current credit_logs of the related account in credit_logs.index
2022-06-15 18:40:52 +02:00
Jérémy Munsch
a178d2e891
Autoriser un multiple de 0.125 sur estimation de ticket 2022-06-15 18:26:16 +02:00
Jérémy Munsch
abcee7b301
Enhance visual tickets display 2022-06-15 18:07:44 +02:00
Jérémy Munsch
95a01f80b8
Ticket 930 fix files.create 2022-06-15 17:26:53 +02:00
Jérémy Munsch
2d077f5d46
Fix sites.add 2022-06-15 17:21:12 +02:00
Jérémy Munsch
9dc1e00f6f
Ticket 936 fix plannings view title z-index 2022-06-15 16:43:41 +02:00
Jérémy Munsch
cccc7743c9
Merge branch 'trunk' 2022-06-14 16:11:41 +02:00
Jérémy Munsch
ab7d676d21
Merge branch 'develop' into trunk 2022-06-14 16:11:33 +02:00
Jérémy Munsch
b3c87ac735
bump and kwaadpepper/exception-handler and update 2022-06-14 16:11:15 +02:00
Jérémy Munsch
77afd066a1
Fix manifest-src 2022-06-14 16:06:24 +02:00
Jérémy Munsch
921d9f5a70
*Merge branch 'trunk' 2022-06-14 09:29:06 +02:00
Jérémy Munsch
5a6b41e4f2
Merge branch 'develop' into trunk 2022-06-14 09:28:50 +02:00
Jérémy Munsch
7baccfc26f
Remove forgotten Label::createDefaultLabelsFor call on Site event 2022-06-14 09:28:16 +02:00
Jérémy Munsch
b759a04fdb
Vue extract styles + CSP enforce 2022-06-10 10:14:40 +02:00
Jérémy Munsch
8ec8c16cd5
Merge branch 'develop' into trunk 2022-06-09 18:53:03 +02:00
Jérémy Munsch
d885ee2f3d
Merge branch 'hotfix' into develop 2022-06-09 18:52:53 +02:00
Jérémy Munsch
e1ae80a9e1
Merge branch 'hotfix' 2022-06-09 18:51:51 +02:00
Jérémy Munsch
b13059715d
Revert to unsafe inline force by vuejs style loader
https://github.com/vuejs/vue-style-loader/issues/33
2022-06-09 18:51:40 +02:00
Jérémy Munsch
ef707a48b6
Merge branch 'hotfix' 2022-06-09 18:32:52 +02:00
Jérémy Munsch
2d141d74ed
Fix CSP CKeditor directives missing semi colon 2022-06-09 18:32:35 +02:00
Jérémy Munsch
ead885799f
Merge branch 'trunk' 2022-06-09 18:26:29 +02:00
Jérémy Munsch
63b619909e
Merge branch 'develop' into trunk 2022-06-09 18:25:44 +02:00
Jérémy Munsch
93724329ff
bump version to 1.2.1 2022-06-09 18:23:19 +02:00
Jérémy Munsch
ec3d0ca044
Remove the need of css unsafe-inline 2022-06-09 18:23:18 +02:00
Olivier Legat
aec2bd8f50 Merge branch 'develop' into trunk 2022-06-09 16:59:02 +02:00
Olivier Legat
9bc9b459b2 Merge branch 'hotfix' into develop 2022-06-09 16:58:40 +02:00
Olivier Legat
959c102a68 Merge branch 'hotfix' 2022-06-09 16:58:14 +02:00
Olivier Legat
2f87824f44
fix regression on tmpPass 2022-06-09 16:57:24 +02:00
Jérémy Munsch
fc4450922a
Merge branch 'hotfix' 2022-06-09 13:48:44 +02:00
Jérémy Munsch
35111a9d5b
Merge branch 'develop' into trunk 2022-06-09 13:47:00 +02:00
Jérémy Munsch
840701e27a
Merge branch 'hotfix' into develop 2022-06-09 13:45:59 +02:00
Jérémy Munsch
9c1b540703
FIX CSP issues
- bumped crud-policies to 0.4.2
- compile vue using runtime and production mode
2022-06-09 13:37:13 +02:00
Jérémy Munsch
f3a20682f0
Fixed new ticket 2022-06-09 12:11:27 +02:00
Jérémy Munsch
79f9b67d3e
Force scheme https always 2022-06-09 12:03:49 +02:00
Olivier Legat
6bf066b4dd Merge branch 'master' of https://voight001.lesidc.com/supportweb 2022-06-09 10:29:42 +02:00
Olivier Legat
cd0cbd45aa Merge branch 'trunk' 2022-06-09 10:29:02 +02:00
Jérémy Munsch
033175bb1d
Merge branch 'develop' into trunk 2022-06-08 09:24:39 +02:00
Jérémy Munsch
134e353a39
Hotfix remove Acount association from brands.create and edit 2022-06-08 09:24:08 +02:00
Jérémy Munsch
347bf77d43
Merge branch 'develop' into trunk 2022-06-08 08:58:10 +02:00
Jérémy Munsch
01cbf534c9 1.2.0
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEENM6P8RR0Fd/BNUDJGDYa87/sD+wFAmKWNmoACgkQGDYa87/s
 D+wA1A/+IutN5JHHYkRo/BSkZftC7JrWF6riKLsknHjHbiqsizVO1A0fm2n8ceND
 i+OI0jgesJ1lJopflHQ0SGTM4OeoYOfRqhZWv/L9LG4J4H6NYEPDcyiEmdPzbNCU
 M5y2ftOPXF9/jPoUQLT0BpcnxFYXDGViC6rzPPV3qKmQp8LeMS8RquraU4gu0dj8
 ESUUAwZjdABfabk6FQInNelukRq0IQSyn/8vD8NlWDR6jsGAAZGUBlXjekKZqlR1
 r3O8q5wL0aSQ2xXLp6SEewcZIDbAbSv53yCjnzA7ji0CfsWXcjRMFKrbwOtQb43z
 li3OwXRYgDXJ65ezyHMiAHwFwmYCxjhnVf918hifqm6fMQdwueOEZxitnr+dtAt5
 yIUm8xoXoQPnUV07r2jZTEL4W6rlPXvNkjLCuOnAZTUdRBGljCIN/iiTNhC7hXA8
 GSpX3LV6io0c24AtAEt1GdvBiknFImLbmP48lqUl/18KGVKG0Ofuvl4KaDTvhBem
 bjN9dS6xuKcjksTLyAcTgI06pu14EOqgX5TybojkLUpzDL3add+piqACxvUoAHgt
 1tEFbl51s9NYEwlWxojgkB1LsTj2RDZuClwLel2D98DOMaIgBZkcoXV7sqSOdUsL
 Qbt1LbhsWRVxWwqAfZk6acfU3wijRVR9NSh2VrEEj93kZgrFiGg=
 =AJ0t
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEENM6P8RR0Fd/BNUDJGDYa87/sD+wFAmKgSHsACgkQGDYa87/s
 D+wDWRAAq6ncCnBW4UJNHg3XJe9faJrL3QJwk45SknPLJMD3cs3M2Fiz6arXcrVL
 N2KMM3VPH16/rEdHeXh2e0LWrHEkDdp6Hvp7xxsQVhuU9vXcmq6bA/ZfG3YkeakS
 g6B44ZlOlbzZnOP+d9WMfo6DNyNvz4ZyA1DW3n04I30qSFPIYf5t6yYwWOiIc+ad
 Hi2PBNZml7QDfRJ2hKB6G5ifUF4WyOYyp6PM5fKriWUsiqSvUE5hj8AiajTlKpnp
 g3m3/3mu/04gKymgsA95wydyBrdDKdVAzbVcAbo0fcFxf/eTlHprJc2elwWD9Bco
 yeQu5lpRrz/wn3oqgvM2+NYClcneFc5sDZiHEqDpRgHdvYqQ3Yhgy48M51zo7I41
 Wag7xe2kYSh8naDMbK9DSECLVgyygiSAgf/38zrV6cTVdyfLiZkFCKFfzti0Iy8p
 d1cWb8pkxGJ80WtLPwFopm3+dk0ktjoiGIfC4S5MirvGGnUQeUZF4VZPQUN+TUJh
 WCuBUaClH8nHKnIt/OOZ0BwbO9GjrMG46X9/W+ru+Gqg84FGdAvSj35vCfwM9Kb1
 9+Fr7yqoBx+9J+e9oYwnZvZDnX8wo2hdzsdm2yVeM4Xfd7SzR4sV0VwhMjsB2P2m
 sMycCopLHuVahAJD7o8tvzYztZ5Iz5SYCHzfeDJDcNyYPRQsDJU=
 =r5eW
 -----END PGP SIGNATURE-----

Merge tag '1.2.0' into develop

1.2.0
2022-06-08 08:58:01 +02:00
Jérémy Munsch
aad7dc9fcc
Merge branch 'develop' into trunk 2022-05-25 11:13:31 +02:00
Vincent BRIDIER
205342cf4a Merge remote-tracking branch 'origin/EVOSW' into develop 2022-05-25 10:04:18 +02:00
Vincent BRIDIER
4ab7525f43 Merge branch 'trunk' 2022-05-25 09:56:57 +02:00
Vincent BRIDIER
56f90ffdb2 Merge branch 'develop' into trunk 2022-05-25 09:56:10 +02:00
Jérémy Munsch
1694d2715a
Fix #793 : Add sites on projects.edit 2022-05-24 09:47:58 +02:00
Jérémy Munsch
9f8c60f487
Merge branch 'trunk' 2022-05-23 14:35:25 +02:00
Jérémy Munsch
d0ef07af28 1.0.9 Macro planning Release
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEENM6P8RR0Fd/BNUDJGDYa87/sD+wFAmKLe4gACgkQGDYa87/s
 D+wuZBAA4j+2qQFS0MB2lWW94thYWGI1HiHioexeB6a9hJ5CjDLGSTIR70m72/YU
 k2CeXuSY/VbEfPPQzIBzxx/B1tkkd79ZlxSM20TRWsPg0BMXKBXclT2cJ2VnJ1is
 b3zXZ5vbNoigKBWa5bIRhGgEhdX/Y6ggEpgpohj69ndeGL4TPqIxrTMtO2Y6EfZY
 ZvNNI/tkEoOEdXiZvcGXOf5L161u+7glf/bFyAzDtjhBvKWN+5epp2IBa0+hEnoA
 Pq+4C2u7B6zBHTuc8G/xy1go7FgX3C5PWnJXZit9vMnLxgdLO8mKbJS8ZtnWozvp
 o0QSbgQOxZzIIbaBRtUfuVO9rbDapmHxip1zt8xAeedP8COzBF/EsoSbl7HA00Zb
 UAnQ4hHj3W4XNNhl4qjmZXrXi+wne9DJB8Gbv8hVk0cd6VPhOmoUvweOHVE3Mll+
 Jm779kfYnJPQzu5msp93RBtOAgKFJzx+6l+vBu7pD4cf/6Sy2yi8zUZ+BnDP+GTa
 816GVwljuf4B4e2pplsftH0EfQLR3gabFuS1Hx1DskWdE1xf8MgmiC2N6hGxi698
 OuhM7qLEbdoeeCEuseLkdD6Qlzuo9szRl7YFNiQcbo4f3n4qP/l2zIZOcMqAF1xM
 I5RtcMZWfHzj1T9hH/+e5W47gBUA2G+YsQBxZXPvQihEs2Ihjfc=
 =ATj/
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEENM6P8RR0Fd/BNUDJGDYa87/sD+wFAmKLe60ACgkQGDYa87/s
 D+xotw//auM7sIxAM1P1vqvQypKvXqau95ikEoTETCeJpQvaK9vS22hY1EfmJSNA
 pJkXBYvJG5TNuNYBdiDKLuh46984X31bWXqVVN8EemvBEkPwhCIxsQqM/gR5wJ9y
 0DNrhMMR498O1rw05jjCUufmWquuDcl4nVOjUca1OlZI2Ib9Tym93YBcTYKNC5gz
 WwWR7A/6UFNkRBQhzYc2gN7kkdUzb50fMRTq6sOJi5v5dvMZigcWfjnJYYcO0MR3
 1w9nPfKPVcwQ6B4e5xIEZtIspcvvOvSvrcB60ez2gBzWZOTfbtG5CoSkrYr8IM1A
 TJUD79lcQu33WEbmOJKg5twJCLU1m5NSDZiHyhmMLGKdtQRE+j5G3xTVV9saLhl2
 2I9al29mh4gyzjEm/Tg6rAEO477OYrBBNCCOxxKSCg4nqzpp8Gp7DJzSpERQqJZu
 Cm1ZN0LUXvn7rPadWKHhgfUvadleQak7XquuvgkKvLwRk8K9CpRVn0oEhcFLpyJM
 MDpym2WZNt1H4CQ37avhTjhldSNJJkH/ScU4aZ2h2LOiTMQRuDxSz8v2Ug21UbkM
 nlP2QMOAzqfIIbkcSNUOpwefbXIrhnjB6loT+ldVQ+TkGlvkn4UMX8ecXQCZ+u5N
 cE+0oCpA4x2Eo92ZndMBwyNfudTC+4PINPP0gKdWQF4sSqfZuZk=
 =t/Wf
 -----END PGP SIGNATURE-----

Merge tag '1.0.9' into trunk

1.0.9 Macro planning Release
2022-05-23 14:18:53 +02:00
Vincent BRIDIER
4824d9ee18
Merge branch 'trunk' 2022-05-23 13:09:57 +02:00
Vincent BRIDIER
6f78838a4c
Merge branch 'develop' into trunk 2022-05-23 13:09:19 +02:00
Jérémy Munsch
ef55965912
Merge branch 'develop' into trunk 2022-05-09 10:38:01 +02:00
Jérémy Munsch
926e7ceba1
Merge branch 'develop' into trunk 2022-05-09 10:20:49 +02:00
Olivier Legat
9915f2b5d5 Merge branch 'trunk' 2022-04-22 08:02:30 +02:00
Olivier Legat
3f0a41f085 Merge branch 'develop' into trunk 2022-04-22 08:02:10 +02:00
Vincent BRIDIER
325377f970
Merge branch 'trunk' 2022-04-20 09:26:27 +02:00
Vincent BRIDIER
943d0cbeb4
Merge branch 'develop' into trunk 2022-04-20 09:26:13 +02:00
Vincent BRIDIER
be7e5e7501
Merge branch 'trunk' 2022-04-13 12:32:20 +02:00
Vincent BRIDIER
9da9eb66d1
Merge branch 'develop' into trunk 2022-04-13 12:32:02 +02:00
Vincent BRIDIER
8e6eb79a00
Merge branch 'trunk' 2022-04-12 16:21:40 +02:00
Vincent BRIDIER
3d060e2e7f
Merge branch 'develop' into trunk 2022-04-12 16:21:16 +02:00
Jérémy Munsch
85ade15303
Merge branch 'trunk' 2022-04-01 15:22:35 +02:00
Jérémy Munsch
29e3f640d5
Merge branch 'develop' into trunk 2022-04-01 15:22:06 +02:00
Vincent BRIDIER
488f3e7ea2
Merge branch 'trunk' 2022-04-01 14:57:26 +02:00
Vincent BRIDIER
007932a259
Merge branch 'develop' into trunk 2022-04-01 14:57:01 +02:00
Vincent BRIDIER
3a866c0a97
Merge branch 'trunk' 2022-03-31 18:32:20 +02:00
Vincent BRIDIER
ab2a7ac2b5
Merge branch 'develop' into trunk 2022-03-31 18:32:02 +02:00
Olivier Legat
318d52f718 Merge branch 'trunk' 2022-03-31 17:55:14 +02:00
Olivier Legat
4994f26bda Merge branch 'develop' into trunk 2022-03-31 17:54:49 +02:00
Olivier Legat
3c770e173c Merge branch 'trunk' 2022-03-15 17:36:00 +01:00
Olivier Legat
c31695bc46 Merge branch 'develop' into trunk 2022-03-15 17:35:47 +01:00
Olivier Legat
c59c97c1b0 Merge branch 'trunk' 2022-03-08 12:11:40 +01:00
Olivier Legat
c790fdf63d Merge branch 'develop' into trunk 2022-03-08 12:11:28 +01:00
Olivier Legat
89d4868fb4 Merge branch 'trunk' 2022-03-08 11:53:38 +01:00
Olivier Legat
3a88eefe63 Merge branch 'develop' into trunk 2022-03-08 11:53:22 +01:00
Olivier Legat
3480a97af2 Merge branch 'trunk' 2022-03-08 11:45:28 +01:00
Olivier Legat
159960801f Merge branch 'develop' into trunk 2022-03-08 11:45:18 +01:00
Olivier Legat
0abc8c2c38 adjust enum for 8 slots 2022-03-08 11:45:03 +01:00
Olivier Legat
95a0615d29 Merge branch 'trunk' 2022-03-08 11:39:35 +01:00
Olivier Legat
759ba1c6d2 Merge branch 'develop' into trunk 2022-03-08 11:39:22 +01:00
Vincent BRIDIER
270d0c1904 Merge branch 'trunk' 2022-02-23 15:43:29 +00:00
Vincent BRIDIER
8f5def1a8e Merge branch 'develop' into trunk 2022-02-23 15:42:24 +00:00
Vincent BRIDIER
1b0e9e3959 Merge branch 'trunk' 2022-02-23 15:29:33 +00:00
Vincent BRIDIER
58d27aafd4 Merge branch 'develop' into trunk 2022-02-23 15:29:08 +00:00
Vincent BRIDIER
1c205d0b92 Merge branch 'trunk' 2022-02-23 15:17:21 +00:00
Vincent BRIDIER
35a565cd8f Merge branch 'develop' into trunk 2022-02-23 15:16:46 +00:00
Olivier Legat
8a9b94b67b Merge branch 'trunk' 2022-02-22 17:06:19 +01:00
Olivier Legat
45b44f45ab Merge branch 'develop' into trunk 2022-02-22 17:06:04 +01:00
Vincent BRIDIER
cd67815ed6 Merge branch 'trunk' 2022-02-11 11:21:18 +01:00
Vincent BRIDIER
ba8ddc72b5 Merge branch 'develop' into trunk 2022-02-11 11:18:26 +01:00
Vincent BRIDIER
65908b23a3 Merge branch 'trunk' 2022-02-09 14:43:52 +00:00
Vincent BRIDIER
649c999693 Merge branch 'develop' into trunk 2022-02-09 14:43:25 +00:00
Vincent BRIDIER
1b4025ff48 Merge branch 'trunk' 2022-02-09 13:12:34 +00:00
Vincent BRIDIER
07924550f8 Merge branch 'develop' into trunk 2022-02-09 13:12:07 +00:00
Jérémy Munsch
87672410eb
Merge branch 'trunk' 2022-02-02 16:48:06 +01:00
Jérémy Munsch
3f74e52fd7
Merge branch 'develop' into trunk 2022-02-02 16:47:58 +01:00
Jérémy Munsch
e08a88774c
Merge branch 'trunk' 2022-02-02 13:52:16 +01:00
Jérémy Munsch
d720056828
Merge branch 'develop' into trunk 2022-02-02 13:51:59 +01:00
Olivier Legat
9dd3f648bd Merge branch 'trunk' 2022-01-24 17:33:05 +01:00
Olivier Legat
d083ea8a06 Merge branch 'develop' into trunk 2022-01-24 17:32:52 +01:00
Olivier Legat
5365bd5ac6 Merge branch 'trunk' 2022-01-03 12:53:44 +01:00
Olivier Legat
5409a52b12 Merge branch 'develop' into trunk 2022-01-03 12:53:31 +01:00
Olivier Legat
cfe9c1ad1b Merge branch 'trunk' 2022-01-03 12:44:46 +01:00
Olivier Legat
5afdfbd5be Merge branch 'develop' into trunk 2022-01-03 12:44:33 +01:00
Olivier Legat
dbace0d0d3 Merge branch 'trunk' 2022-01-03 12:32:57 +01:00
Olivier Legat
d641208a44 Merge branch 'develop' into trunk 2022-01-03 12:32:32 +01:00
Jérémy Munsch
e550b9bc82
Merge branch 'trunk' 2021-12-09 11:40:30 +01:00
Jérémy Munsch
512d5525ef
Merge branch 'develop' into trunk 2021-12-09 11:40:29 +01:00
Jérémy Munsch
b08539755c
Merge branch 'trunk' 2021-12-03 14:45:55 +01:00
Jérémy Munsch
1aab63316e
Merge branch 'develop' into trunk 2021-12-03 14:45:53 +01:00
Jérémy Munsch
bb64bedf38
Merge branch 'trunk' 2021-12-01 13:49:23 +01:00
Jérémy Munsch
7b8e3c5035
Merge branch 'develop' into trunk 2021-12-01 13:49:21 +01:00
Jérémy Munsch
27da04b405
Merge branch 'trunk' 2021-12-01 13:47:33 +01:00
Jérémy Munsch
a6e112cbd7
Merge branch 'develop' into trunk 2021-12-01 13:47:31 +01:00
Jérémy Munsch
1b1ae0cf2b
Merge branch 'trunk' 2021-12-01 13:46:28 +01:00
Jérémy Munsch
6d6aa4eec0
Merge branch 'develop' into trunk 2021-12-01 13:46:24 +01:00
Jérémy Munsch
0183748219
Merge branch 'trunk' 2021-12-01 13:40:44 +01:00
Jérémy Munsch
72fa30ca72
Merge branch 'develop' into trunk 2021-12-01 13:40:34 +01:00
Jérémy Munsch
dfa6ba7a71
Merge branch 'trunk' 2021-12-01 13:31:32 +01:00
Jérémy Munsch
4e5967af40
Merge branch 'develop' into trunk 2021-12-01 13:31:31 +01:00
Jérémy Munsch
7f47cd8585
Merge branch 'trunk' 2021-11-15 14:39:30 +01:00
Jérémy Munsch
ce9d683505
Merge branch 'develop' into trunk 2021-11-15 14:39:29 +01:00
Jérémy Munsch
b251605fa3
Merge branch 'trunk' 2021-11-15 14:32:09 +01:00
Jérémy Munsch
08623af7a3
Merge branch 'develop' into trunk 2021-11-15 14:31:58 +01:00
Olivier Legat
775409f7e3 Merge branch 'trunk' 2021-11-02 09:04:46 +01:00
Olivier Legat
0da3b122a9 Merge branch 'develop' into trunk 2021-11-02 09:04:27 +01:00
Jérémy Munsch
b71405734b
Merge branch 'trunk' 2021-10-26 12:15:55 +02:00
Jérémy Munsch
b58a8cc5ee 1.0.5
-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEEbXCAeh4tnJbE5ao1VRlr7kRfYEkFAmF31UQACgkQVRlr7kRf
 YEnz2Qv/dg0JDJCpRfdhg8tZo790oWl2csv7UqQeaI5G1Au6dIbRnUJ9pgMQ9LLz
 TNmgeZrCLQLCIIPNwCkcV8tSWlyRVMLyLejq44K9jAXzB47h61J78Kzj2mB65p9O
 ncN/J3CcVQYjpypf7Zu0yYgU5GiwPiy/h8NUjs0MdAiCwUlsDHXuTuQ5z6jL4znT
 qUg+WTG6RtW9RpAcoW4yU/Go4McH6HY/F5yyK3SNXttygitlbGlOyln0Q3suPBhS
 mateZzV+e0eEeK2T54awPLDIwNwRU9F+XaeCacSBdnPdJetfKv1I38j1/yPiqOX6
 c4fbFwb2E5I0Eg2gNv6KXQVGz4yAMV/ufv6z9u/tOH6S/uLKUquWiC3HISBaT6rA
 E1g2VKjn7PeeZM2+uQ+nIzUe1aGfNVP+Ntf1maUWedaunj3nD/Cp74FPy2wzUZoa
 scd8uQqNVVb7Va+mkRyoBKnkS8bpwWbVwS5MGCHImr6em1uJbri9tbthYTsFDdpJ
 WcprVIx3
 =Z1QK
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEEbXCAeh4tnJbE5ao1VRlr7kRfYEkFAmF31VEACgkQVRlr7kRf
 YEkjQQv+KdGC4l+eqcAggxRol7HfopDeEf7NB2e20gE6QeuRXMCIR6i0t86s3R03
 pfcHZmzauFV620wn7RgnDemghHZwPlmEF0y1YAPRl18Xf0rhEw37o9tpObLrSQfI
 y01SHVugTyLPvhWVVsCh227gPHIoQPmqAOuPk2uOLYJtePz+L3inbIZ4+KTURWEZ
 VSa9o5nunWMYPrfi6nRUtJMGLN96/p3lNrQpiIqQH2BI32yIt6AIF6Vc7FdJc5i5
 V/sGt7MU1VJ1XJv0gqIYs7s1rIfciwKxnfN96ZboVVcPwIuqw0+MgyXNfEKobeAc
 3JXmcEwewEotDsLo9iwg9Exi57NU+O2OVbaTsrN02MkAUOs1//ycPrPP2nHSmFU9
 g82nZamnLVCYmTPl2YpucduxFH/vZPK7W1OSrr9fWZ00tTdpdOpigjhhSxnApmga
 aPjHabHU9AkIgQt6cOVrvogrp0zFPUAPVmYP5+gx+hfieotXYxkUO18EUHkKt/Xi
 jQtqujVn
 =bz/t
 -----END PGP SIGNATURE-----

Merge tag '1.0.5' into trunk

1.0.5
2021-10-26 12:15:44 +02:00
Jérémy Munsch
b102a825f3
Merge branch 'trunk' 2021-10-25 13:30:52 +02:00
Jérémy Munsch
b1c7c6a301
Merge branch 'develop' into trunk 2021-10-25 13:30:38 +02:00
Jérémy Munsch
63eec7eb34
Merge branch 'trunk' 2021-10-22 14:03:40 +02:00
Jérémy Munsch
76c226e46c
Merge branch 'develop' into trunk 2021-10-22 14:03:39 +02:00
Olivier Legat
cde565295a Merge branch 'trunk' 2021-10-13 11:21:14 +02:00
Olivier Legat
a26435e493 Merge branch 'develop' into trunk 2021-10-13 11:20:57 +02:00
Olivier Legat
9411dc30f8 Merge branch 'develop' into trunk 2021-10-13 11:02:57 +02:00
Jérémy Munsch
77fc19a8fc
Merge branch 'trunk' 2021-10-05 09:21:30 +02:00
Jérémy Munsch
62dc17aecb
Merge branch 'develop' into trunk 2021-10-05 09:21:29 +02:00
Jérémy Munsch
de2719f011
Merge branch 'trunk' 2021-10-02 14:08:14 +02:00
Jérémy Munsch
211a1f916b
Merge branch 'develop' into trunk 2021-10-02 14:08:12 +02:00
Jérémy Munsch
a2300e9d5c
Merge branch 'trunk' 2021-10-02 14:04:54 +02:00
Jérémy Munsch
275b4e0fad
Merge branch 'develop' into trunk 2021-10-02 14:04:53 +02:00
Jérémy Munsch
237fe89b22
Merge branch 'trunk' 2021-10-02 13:58:40 +02:00
Jérémy Munsch
2d43f071e9
Merge branch 'develop' into trunk 2021-10-02 13:58:39 +02:00
Jérémy Munsch
0f9ac44908
Merge branch 'trunk' 2021-09-30 09:37:21 +02:00
Jérémy Munsch
c15aa5b5ee
Merge branch 'develop' into trunk 2021-09-30 09:37:19 +02:00
Jérémy Munsch
0b6aa1cc34
Merge branch 'trunk' 2021-09-29 13:24:19 +02:00
Jérémy Munsch
08e7c22bf2
Merge branch 'develop' into trunk 2021-09-29 13:24:18 +02:00
Jérémy Munsch
edc269495a
Merge branch 'trunk' 2021-09-29 12:12:51 +02:00
Jérémy Munsch
7161def543
Merge branch 'develop' into trunk 2021-09-29 12:12:50 +02:00
Jérémy Munsch
7c13f3f4f2
Merge branch 'trunk' 2021-09-29 12:05:04 +02:00
Jérémy Munsch
461da56e64
Merge branch 'develop' into trunk 2021-09-29 12:04:59 +02:00
Jérémy Munsch
2d9f30f621
Merge branch 'trunk' 2021-09-29 10:26:19 +02:00
Jérémy Munsch
b8269d30f1
Merge branch 'develop' into trunk 2021-09-29 10:26:11 +02:00
Jérémy Munsch
aa9fb1bcf1
Merge branch 'trunk' 2021-09-29 09:39:37 +02:00
Jérémy Munsch
0b04086cfb
Merge branch 'develop' into trunk 2021-09-29 09:39:31 +02:00
Jérémy Munsch
6da5ce674d
Merge branch 'trunk' 2021-09-29 09:37:03 +02:00
Jérémy Munsch
2fafbfb53e
Merge branch 'develop' into trunk 2021-09-29 09:36:57 +02:00
Jérémy Munsch
9d9f90b46f
Merge branch 'trunk' 2021-09-28 14:56:15 +02:00
Jérémy Munsch
1ab287b3da
Merge branch 'develop' into trunk 2021-09-28 14:56:09 +02:00
Jérémy Munsch
2d65cee66c
Merge branch 'trunk' 2021-09-28 11:41:28 +02:00
Jérémy Munsch
9428ccf3c6
Merge branch 'develop' into trunk 2021-09-28 11:41:18 +02:00
Jérémy Munsch
97205e33c7
Merge branch 'trunk' 2021-09-21 17:15:33 +02:00
Jérémy Munsch
487220806e
Merge branch 'develop' into trunk 2021-09-21 17:15:16 +02:00
Jérémy Munsch
298873f5da
Merge branch 'trunk' 2021-09-21 10:19:43 +02:00
Jérémy Munsch
37a899facd
Merge branch 'develop' into trunk 2021-09-21 10:19:21 +02:00
Vincent BRIDIER
13aaea6909 Merge branch 'master' of https://voight001.lesidc.com/supportweb 2021-08-16 15:25:06 +02:00
Vincent BRIDIER
a7b864ed20 Merge branch 'trunk' 2021-08-16 15:24:56 +02:00
Vincent BRIDIER
5ac61d3c64 Merge branch 'trunk' of https://voight001.lesidc.com/supportweb into trunk 2021-08-16 15:24:27 +02:00
Vincent BRIDIER
d3b324ce1d Merge branch 'develop' into trunk 2021-08-16 15:24:16 +02:00
Jérémy Munsch
50908cdc80 Merge branch 'trunk' 2021-08-09 09:26:01 +02:00
Jérémy Munsch
8121d6393f Merge branch 'develop' into trunk 2021-08-09 09:26:00 +02:00
Jérémy Munsch
36694bba15 Merge branch 'trunk' 2021-08-02 09:40:39 +02:00
Jérémy Munsch
a398b06743 Merge branch 'develop' into trunk 2021-08-02 09:40:38 +02:00
Jérémy Munsch
710bd25f79 Merge branch 'trunk' 2021-08-02 08:38:08 +02:00
Jérémy Munsch
52663ec725 Merge branch 'develop' into trunk 2021-08-02 08:37:47 +02:00
Jérémy Munsch
a90ad6eea4 Merge branch 'trunk' 2021-07-30 09:38:40 +02:00
Jérémy Munsch
dae06beadb Merge branch 'develop' into trunk 2021-07-30 09:38:07 +02:00
aa76c9bec4 Merge branch 'trunk' 2021-07-27 22:00:27 +02:00
c3a1371753 Merge branch 'develop' into trunk 2021-07-27 22:00:08 +02:00
Jérémy Munsch
dec566874c Merge branch 'trunk' 2021-07-27 16:49:51 +02:00
Jérémy Munsch
e210df01d1 Merge branch 'develop' into trunk 2021-07-27 16:49:31 +02:00
Jérémy Munsch
4b2c956c30 Merge branch 'trunk' 2021-07-27 16:29:19 +02:00
Jérémy Munsch
590fc0ace3 Merge branch 'develop' into trunk 2021-07-27 16:29:07 +02:00
Jérémy Munsch
3435cb1803 Merge branch 'trunk' 2021-07-27 16:26:47 +02:00
Jérémy Munsch
3327d7d365 Merge branch 'develop' into trunk 2021-07-27 16:26:35 +02:00
Jérémy Munsch
69a97fc259 Merge branch 'trunk' 2021-07-27 16:13:21 +02:00
Jérémy Munsch
e951e4b2fb Merge branch 'develop' into trunk 2021-07-27 16:13:09 +02:00
Jérémy Munsch
e4006145a2 Merge branch 'trunk' 2021-07-27 15:44:38 +02:00
Jérémy Munsch
3efe638dca Merge branch 'develop' into trunk 2021-07-27 15:44:26 +02:00
Jérémy Munsch
25e380421c Merge branch 'trunk' 2021-07-27 14:51:32 +02:00
Jérémy Munsch
1f10067a71 Merge branch 'develop' into trunk 2021-07-27 14:51:09 +02:00
Jérémy Munsch
f94185dae9 Merge branch 'trunk' 2021-07-27 12:52:07 +02:00
Jérémy Munsch
e23388c2d5 Merge branch 'develop' into trunk 2021-07-27 12:51:54 +02:00
Jérémy Munsch
80e1107c21 Merge branch 'trunk' 2021-07-27 12:28:15 +02:00
Jérémy Munsch
f909b6adf1 Merge branch 'develop' into trunk 2021-07-27 12:28:03 +02:00
Jérémy Munsch
d5bf8d5dc6 Merge branch 'trunk' 2021-07-27 12:20:32 +02:00
Jérémy Munsch
08b97922a7 Merge branch 'develop' into trunk 2021-07-27 12:19:48 +02:00
Jérémy Munsch
851e5860a3 Merge branch 'trunk' 2021-07-27 12:13:49 +02:00
Jérémy Munsch
05da11e9ed Merge branch 'develop' into trunk 2021-07-27 12:13:25 +02:00
Jérémy Munsch
9f6cf01693 Merge branch 'trunk' 2021-07-21 09:45:18 +02:00
Jérémy Munsch
501e09847d Merge branch 'develop' into trunk 2021-07-21 09:45:04 +02:00
Jérémy Munsch
6b1228b816 Merge branch 'trunk' 2021-07-05 18:36:43 +02:00
Jérémy Munsch
dc2da30ff5 Merge branch 'develop' into trunk 2021-07-05 18:36:30 +02:00
Jérémy Munsch
b68a4622f6 Merge branch 'trunk' 2021-06-30 08:56:39 +02:00
Jérémy Munsch
8b381b68fc Merge branch 'develop' into trunk 2021-06-30 08:56:14 +02:00
Jérémy Munsch
3396a6e639 Merge branch 'trunk' 2021-06-29 10:18:28 +02:00
Jérémy Munsch
a3ebd56bfc Merge branch 'develop' into trunk 2021-06-29 10:18:16 +02:00
Jérémy Munsch
a28f7be57a Merge branch 'trunk' 2021-06-29 09:13:44 +02:00
Jérémy Munsch
fab9bdb124 Merge branch 'develop' into trunk 2021-06-29 09:13:21 +02:00
Jérémy Munsch
35af24fad9 Merge branch 'trunk' 2021-06-28 17:43:53 +02:00
Jérémy Munsch
a179236dc5 Merge branch 'develop' into trunk 2021-06-28 17:43:40 +02:00
Jérémy Munsch
9ca912f279 Merge branch 'trunk' 2021-06-28 17:36:21 +02:00
Jérémy Munsch
98d0edb024 Merge branch 'develop' into trunk 2021-06-28 17:34:24 +02:00
Vincent BRIDIER
751ef46ee3 Merge branch 'trunk' 2021-06-24 11:33:22 +02:00
Vincent BRIDIER
e21029d295 Merge branch 'develop' into trunk 2021-06-24 11:32:46 +02:00
Vincent BRIDIER
ee410ee04d Merge branch 'trunk' 2021-06-23 19:49:17 +02:00
Vincent BRIDIER
14c3f4b968 Merge branch 'develop' into trunk 2021-06-23 19:48:48 +02:00
640 changed files with 143372 additions and 30289 deletions

5
.browserslistrc Normal file
View file

@ -0,0 +1,5 @@
# Browsers that we support
last 3 version
> 0.3%
not dead # no browsers without security updates

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
.git
*.md

View file

@ -3,9 +3,9 @@ root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
@ -13,3 +13,9 @@ trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4
[*.vue]
indent_size = 2

View file

@ -5,6 +5,7 @@ APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
@ -16,6 +17,7 @@ DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
@ -28,5 +30,18 @@ MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=noreply-sw@ldc.fr
MAIL_FROM_NAME="${APP_NAME}"
MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr
MAIL_ADMIN=equipe.web@ldc.fr
MAIL_LIST_SERVICEWEB=digital@ldc.fr
MAIL_ADMIN=digital@ldc.fr
# Sentry
SENTRY_LARAVEL_DSN=
# UWIL ADMIN SECURE
# - LIST SEPARATED WITH ',' (Required)
UWIL_ADMIN_SECURE_CIDR_LIST=""
# - LIST SEPARATED WITH ',' (Optional)
UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST=
# GITLAB API
GITLAB_URL=
GITLAB_TOKEN=

55
.eslintrc.json Normal file
View file

@ -0,0 +1,55 @@
{
"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"
},
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".vue", ".ts", ".d.ts"]
},
"alias": {
"extensions": [".vue", ".js", ".ts", ".scss", ".d.ts"],
"map": [
["~", "./resources/assets"],
["@", "./node_modules"]
]
}
}
}
}

14
.gitattributes vendored
View file

@ -1,5 +1,11 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore

34
.gitignore vendored
View file

@ -1,20 +1,28 @@
/node_modules
/public/hot
/public/storage
/public/fichiers
/public/*
/storage/*.key
/vendor
.vscode
.env
.env.backup
.env.dev
.env.prod
.env.production
.phpunit.result.cache
.stylelintcache
/.fleet
/.idea
/.phpunit.cache
/.vscode
/node_modules
/public/build
/public/cache
/public/hot
/public/sitemap.xml
/public/storage
/storage/*.key
/vendor
auth.json
docker-compose.override.yml
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
package-lock.json
composer.lock
.idea/
storage/samlidp/*
.npmrc
.zshrc
.npm/
.composer/

24
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,24 @@
include:
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'lint/lint.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'security/security.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: "build/docker-multistage.yml"
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'test/test.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'deploy/deploy.yml'
stages:
- lint
- security
- build
- test
- deploy

View file

@ -0,0 +1,11 @@
## Comportement constaté
## Comportement attendu
## Solution envisagée
## Étapes pour la reproduction du bug
*

View file

@ -0,0 +1,7 @@
## Présentation du besoin
## Implémentation
## Maquettes, documentations...

View file

@ -1,13 +0,0 @@
php:
preset: laravel
disabled:
- no_unused_imports
finder:
not-name:
- index.php
- server.php
js:
finder:
not-name:
- webpack.mix.js
css: true

45
.stylelintrc.json Normal file
View file

@ -0,0 +1,45 @@
{
"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": {
"declaration-property-value-no-unknown": true,
"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-newline-after": null,
"value-list-comma-newline-after": null,
"scss/double-slash-comment-empty-line-before": [
"always",
{
"ignore": [
"between-comments",
"stylelint-commands",
"inside-block"
]
}
]
}
}

View file

@ -1,12 +1,13 @@
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#3371a9",
"activityBar.activeBorder": "#621e41",
"activityBar.activeBackground": "#3371a9",
"activityBar.background": "#3371a9",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
"activityBarBadge.background": "#621e41",
"activityBarBadge.foreground": "#e7e7e7",
"commandCenter.border": "#e7e7e799",
"sash.hoverBorder": "#3371a9",
"statusBar.background": "#275782",
"statusBar.foreground": "#e7e7e7",

View file

@ -1,3 +1,30 @@
### 25.04.2023 -> 1.4.0
- Add ticket types management
- Fix AutoClose Jobs
- Fix Email notifications on private messages
### 04.2023 -> 1.3.0
- Update Status Enum
- Update TicketStatusChanged event
- Update TicketStatus Changed messages
- Add DutyHours
- Add Informations
### 15.12.2022
- Add Sentry
### 12.10.2022 -> 1.2.3
- Hotfixed regular users could not create tickets anymore
### 01.07.2022 -> 1.2.2
- Fixed CSP directives
- Fixed multiples bugs
- Fixed View sur crédits
- Fixed file create
- Changed estimation can be 0.125 days
- Fixed files view
- Added ticket link on credit log
### 09.06.2022 -> 1.2.1
- CSP rules enforce
- Bug fixes CSP issues
### 31.05.2022 -> 1.2.0
- Ajout de la fonctionnalitée d'estimations

43
Dockerfile Normal file
View file

@ -0,0 +1,43 @@
FROM composer:2.9.2 AS vendor
ARG GITLAB_USER
ARG GITLAB_PASSWORD
COPY database/ database/
COPY composer.json composer.json
COPY composer.lock composer.lock
RUN composer config gitlab-token.lab.s-web.fr ${GITLAB_USER} ${GITLAB_PASSWORD}
RUN composer install \
--ignore-platform-reqs \
--no-interaction \
--no-plugins \
--no-scripts \
--no-dev \
--prefer-dist
FROM node:20.18 AS frontend
ARG GITLAB_PASSWORD
RUN mkdir -p /app/public/build
COPY package*.json tsconfig.json vite.config.ts .eslintrc.json .stylelintrc.json /app/
COPY resources/ /app/resources/
WORKDIR /app
RUN npm config set @uwil:registry https://lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/
RUN npm config set -- '//lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
RUN npm ci --no-audit --no-fund --loglevel=error && npm run prod
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
ARG USER=www-data
COPY --chown=${USER}:${USER} . /app/srcs
COPY --from=vendor --chown=${USER}:${USER} /app/vendor/ /app/srcs/vendor/
COPY --from=frontend --chown=${USER}:${USER} /app/public/build/ /app/srcs/public/build/
USER root
RUN chmod -R 755 /app/srcs/storage
USER ${USER}

View file

@ -1,11 +1,3 @@
- Permettre à un user de suivre un projet
- ~~permettre d'insérer des @user dans le texte avec lien vers user~~
~~pas de liens vers user mais mise en form~~
- ~~parse de @user + envoie de mail si un seul user est trouvé~~
- ~~permettre de modifier son mot de passe ? (je crois que ça n'as pas été mis exprès)~~
- ~~parser les liens http~~
Algorithme charge de travail ticket

17
README.md Normal file
View file

@ -0,0 +1,17 @@
# UWIL Support
PROD : support.uwil.fr
RE7 : support-web.re7-s-web.fr
## Gitlab Intégration
Le token de groupe pour l'intégration est valable 11 mois
Il faut le renouveler ici : https://lab.s-web.fr/groups/ldc-web/projets/-/settings/access_tokens et le nommer SW Intégration
Role : Guest
Scope : api
## TODO
- App\Models\Message:booted(): investigate why this make errors on prod,

4633
_ide_helper.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands;
use App\Jobs\AutoCloseOldTickets as JobsAutoCloseOldTickets;
use Illuminate\Console\Command;
class AutoCloseOldTickets extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tickets:auto-close-old';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run the AutoCloseOldTickets job.';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
$this->info('Running the Job, this could take some time.');
$job = new JobsAutoCloseOldTickets();
$job->handle();
$this->info('Job completed');
return 0;
}
}

View file

@ -2,10 +2,11 @@
namespace App\Console\Commands;
use App\Enums\Role;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class CreateUser extends Command
{
@ -14,7 +15,7 @@ class CreateUser extends Command
*
* @var string
*/
protected $signature = 'create:user';
protected $signature = 'user:create';
/**
* The console command description.
@ -23,6 +24,34 @@ class CreateUser extends Command
*/
protected $description = 'Create a user';
/**
* The name of the new user.
*
* @var string
*/
protected $name;
/**
* The email of the new user.
*
* @var string
*/
protected $email;
/**
* The password of the new user.
*
* @var string
*/
protected $password;
/**
* The role of the new user.
*
* @var integer
*/
protected $role;
/**
* Execute the console command.
*
@ -30,21 +59,110 @@ class CreateUser extends Command
*/
public function handle()
{
$name = $this->ask('What is the name?');
$email = $this->ask('What is the email?');
$pwd = $this->secret('What is the password?');
$user = new User();
$user->name = $name;
$user->email = $email;
if ($this->confirm('Is the user an admin?')) {
$user->role = Role::admin();
} else {
$user->role = Role::client();
}
$user->password = Hash::make($pwd);
$user->save();
$this->name = null;
$this->addName();
$this->email = null;
$this->addEmail();
$this->password = null;
$this->addPassword();
$this->role = null;
$this->addRole();
$user = new User([
'name' => $this->name,
'email' => $this->email,
'password' => $this->password,
'role' => $this->role
]);
$user->saveOrFail();
$this->info('User created.');
return 0;
}
/**
* Add a firstname to the user.
*
* @return void
*/
private function addName(): void
{
while (is_null($this->name)) {
try {
$tmp = $this->ask('Type the wanted user name', 'Admin');
$validator = Validator::make(['name' => $tmp], [
'name' => 'required|min:3|max:255'
]);
$validator->validate();
$this->name = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid name %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
/**
* Add an email to the user.
*
* @return void
*/
private function addEmail(): void
{
while (is_null($this->email)) {
try {
$tmp = $this->ask('Type the wanted user email', 'digital@ldc.fr');
$validator = Validator::make(['email' => $tmp], [
'email' => 'required|unique:users,email|email:rfc,dns'
]);
$validator->validate();
$this->email = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid email %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
/**
* Add a password to the user.
*
* @return void
*/
private function addPassword(): void
{
while (
($this->password = $this->secret(
(!\is_null($this->password) ? 'Failed to confirm, ' : '') . 'Type the wanted user password'
)) !== $this->secret('Confirm the password')
) {
continue;
}; //end while
}
/**
* Add a password to the user.
*
* @return void
*/
private function addRole(): void
{
while (is_null($this->role)) {
$tmp = $this->confirm('Is the user an admin?');
$validator = Validator::make(['role' => $tmp], [
'role' => 'required|boolean'
]);
$validator->validate();
$this->role = $tmp ? RoleEnum::admin : RoleEnum::client;
};
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands;
use App\Jobs\ExportTicketsState as JobsExportTicketsState;
use Illuminate\Console\Command;
class ExportTicketsState extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tickets:export-state';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Export the state of tickets to a CSV file';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
$this->info('Running the Job, this could take some time.');
$job = new JobsExportTicketsState();
$job->handle();
$this->info('Job completed');
return 0;
}
}

View file

@ -1,77 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
/*
* Command Name: LDC Web Status Checker
* Description: Envoi des infos Serveur/Laravel vers LDC Web
* Version: 1.1
* Author: Vincent BRIDIER
* Author URI: vincent.bridier@ldc.fr
*/
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);
curl_exec($ch);
curl_close($ch);
return 0;
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class TestMail extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:mail-test';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send test email to digital@ldc.fr';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
Mail::raw(sprintf('UWIL mail-test from %s %s', \config('app.name'), \config('app.url')), function ($msg) {
$msg->to('digital@ldc.fr')->subject('Test Email');
});
return 0;
}
}

View file

@ -0,0 +1,334 @@
<?php
namespace App\Console\Commands;
use App\Enums\Tickets\TicketStatusEnum;
use App\Models\GitlabIssues;
use App\Models\GitlabLabels;
use App\Models\GitlabMilestones;
use App\Models\GitlabProjects;
use App\Models\Ticket;
use Carbon\Carbon;
use GrahamCampbell\GitLab\Facades\GitLab;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class UpdateGitlabDatas extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:update-gitlab-datas {--is-cron}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fetch some Gitlab datas';
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$isCron = $this->option('is-cron');
$groupId = 23;
$this->updateProjectsByGroup($groupId);
$this->updateLabelsByGroup($groupId);
$projects = GitlabProjects::all();
foreach ($projects as $project) {
$this->updateMilestonesByProject($project);
$this->updateIssuesByProject($project, $isCron);
}
$this->syncTicketStatus();
}
/**
* updateProjectsByGroup function
*
* @param integer $groupId
* @return void
*/
private function updateProjectsByGroup(int $groupId): void
{
$allProjects = [];
$page = 1;
do {
$projects = GitLab::groups()->projects($groupId, [
'order_by' => 'created_at',
'sort' => 'asc',
'per_page' => 100,
'page' => $page,
'include_subgroups' => true
]);
$allProjects = array_merge($allProjects, $projects);
$page++;
} while (!empty($projects));
$this->info(sprintf(
"Fetched %d projects in group %d.",
count($allProjects),
$groupId
));
foreach ($allProjects as $project) {
GitlabProjects::upsert(
[
'name' => $project['name'],
'url' => $project['web_url'],
'is_archived' => $project['archived'],
'gitlab_id' => $project['id']
],
['gitlab_id']
);
}
$this->info("Gitlab Projects upsert complete.");
}
/**
* updateLabelsByGroup function
*
* @param integer $groupId
* @return void
*/
private function updateLabelsByGroup(int $groupId): void
{
$allLabels = [];
$page = 1;
do {
$labels = GitLab::groups()->labels($groupId, [
'per_page' => 100,
'page' => $page,
]);
$allLabels = array_merge($allLabels, $labels);
$page++;
} while (!empty($labels));
$this->info(sprintf(
"Fetched %d labels in group %d.",
count($allLabels),
$groupId
));
foreach ($allLabels as $project) {
GitlabLabels::upsert(
[
'name' => $project['name'],
'gitlab_id' => $project['id']
],
['gitlab_id']
);
}
$this->info("Gitlab labels upsert complete.");
}
/**
* updateIssuesByProject function
*
* @param GitlabProjects $project
* @param boolean $isCron
* @return void
*/
private function updateIssuesByProject(GitlabProjects $project, bool $isCron = false): void
{
$projectId = $project->gitlab_id;
$allIssues = [];
$page = 1;
do {
$params = [
'order_by' => 'created_at',
'sort' => 'asc',
'per_page' => 100,
'page' => $page,
'state' => 'all',
];
if ($isCron) {
$params = array_merge($params, ['updated_after' => now()->subDay()]);
}
$issues = GitLab::projects()->issues($projectId, $params);
$allIssues = array_merge($allIssues, $issues);
$page++;
} while (!empty($issues));
$this->info(sprintf(
"Fetched %d issues in project %d.",
count($allIssues),
$projectId
));
foreach ($allIssues as $issue) {
GitlabIssues::upsert(
[
'title' => $issue['title'],
'url' => $issue['web_url'],
'estimate_time' => $issue['time_stats']['time_estimate'] ?? 0,
'spent_time' => $issue['time_stats']['total_time_spent'] ?? 0,
'is_closed' => $issue['state'] === 'closed',
'gitlab_id' => $issue['id'],
'gitlab_iid' => $issue['iid'],
'milestone_iid' => $issue['milestone']['iid'] ?? null,
'gitlab_project_id' => $projectId,
'g_created_at' => Carbon::parse($issue['created_at'])->format('Y-m-d'),
'g_updated_at' => Carbon::parse($issue['updated_at'])->format('Y-m-d'),
'g_closed_at' => !is_null($issue['closed_at'])
? Carbon::parse($issue['closed_at'])->format('Y-m-d')
: null,
'g_due_date' => !is_null($issue['due_date'])
? Carbon::parse($issue['due_date'])->format('Y-m-d')
: null
],
['gitlab_id']
);
$issueModel = GitlabIssues::where('gitlab_id', $issue['id'])->firstOrFail();
$labelIds = [];
foreach ($issue['labels'] as $labelName) {
$label = Cache::remember("gitlab_label_{$labelName}", 300, function () use ($labelName) {
return GitlabLabels::where('name', $labelName)->first();
});
if ($label) {
$labelIds[] = $label;
}
}
$issueModel->gitlabLabels()->sync($labelIds);
}//end foreach
$this->info("Gitlab issues upsert complete.");
}
/**
* updateMilestonesByProject function
*
* @param GitlabProjects $project
* @return void
*/
private function updateMilestonesByProject(GitlabProjects $project): void
{
$projectId = $project->gitlab_id;
$allMilestones = [];
$page = 1;
do {
$milestones = [];
try {
$milestones = GitLab::milestones()->all($projectId, [
'per_page' => 100,
'page' => $page
]);
} catch (\Exception $e) {
if ($e->getCode() === 404) {
if ($project->delete()) {
Log::warning(sprintf(
"Project not found (%s), it has been deleted.",
$projectId
));
} else {
Log::warning(sprintf(
"Project not found (%s).",
$projectId
));
}
} else {
Log::error(sprintf(
'API Error for project %s, Message: %d',
$projectId,
$e->getMessage()
));
report($e);
}
}
$allMilestones = array_merge($allMilestones, $milestones);
$page++;
} while (!empty($milestones));
$this->info(sprintf(
"Fetched %d milestones in project %d.",
count($allMilestones),
$projectId
));
foreach ($allMilestones as $milestone) {
GitlabMilestones::upsert(
[
'title' => $milestone['title'],
'url' => $milestone['web_url'],
'is_closed' => $milestone['state'] === 'closed',
'gitlab_id' => $milestone['id'],
'gitlab_iid' => $milestone['iid'],
'gitlab_project_id' => $projectId,
'g_created_at' => Carbon::parse($milestone['created_at'])->format('Y-m-d'),
'g_updated_at' => Carbon::parse($milestone['updated_at'])->format('Y-m-d'),
'g_start_date' => !is_null($milestone['start_date'])
? Carbon::parse($milestone['start_date'])->format('Y-m-d')
: null,
'g_due_date' => !is_null($milestone['due_date'])
? Carbon::parse($milestone['due_date'])->format('Y-m-d')
: null
],
['gitlab_id']
);
}//end foreach
$this->info("Gitlab milestones upsert complete.");
}
/**
* Synchronizes ticket statuses based on GitLab issue labels.
*
* @return void
*/
private function syncTicketStatus(): void
{
$tickets = Ticket::whereNotNull('gitlab_issue')->whereNot('status', TicketStatusEnum::archived)->get();
foreach ($tickets as $ticket) {
$gitlabIssue = GitlabIssues::where('url', $ticket->gitlab_issue)->with('gitlabLabels')->first();
$gitlabIssueLabels = $gitlabIssue ? $gitlabIssue->gitlabLabels->pluck('name') : [];
if ($gitlabIssueLabels) {
match (true) {
$gitlabIssueLabels->contains('g-wip') => $this->updateTicketStatus($ticket, TicketStatusEnum::inDev),
$gitlabIssueLabels->contains('g-production') => $this->updateTicketStatus($ticket, TicketStatusEnum::production),
default => null,
};
}
}
}
/**
* Updates the ticket status only if it has changed.
*
* @param Ticket $ticket The ticket to update.
* @param TicketStatusEnum $status The new status to apply.
*
* @return void
*/
private function updateTicketStatus(Ticket $ticket, TicketStatusEnum $status): void
{
if ($ticket->status !== $status && $ticket->status !== TicketStatusEnum::waiting) {
$ticket->status = $status;
$ticket->saveOrFail();
}
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands;
use App\Jobs\WarnBeforeAutoCloseTicket as JobsWarnBeforeAutoCloseTicket;
use Illuminate\Console\Command;
class WarnBeforeAutoCloseTicket extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tickets:warn-before-auto-close';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run the WarnBeforeAutoCloseTicket job.';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
$this->info('Running the Job, this could take some time.');
$job = new JobsWarnBeforeAutoCloseTicket();
$job->handle();
$this->info('Job completed');
return 0;
}
}

View file

@ -3,6 +3,7 @@
namespace App\Console;
use App\Jobs\AutoCloseOldTickets;
use App\Jobs\ExportTicketsState;
use App\Jobs\WarnBeforeAutoCloseTicket;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -24,8 +25,10 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
$schedule->job(ExportTicketsState::class)->weekly()->fridays()->at('14:00');
$schedule->job(AutoCloseOldTickets::class)->dailyAt('08:00');
$schedule->job(WarnBeforeAutoCloseTicket::class)->dailyAt('08:05');
$schedule->command('app:update-gitlab-datas --is-cron')->hourly()->between('7:00', '19:00');
}
/**

View file

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Dto;
final readonly class BrevoWebHookDto
{
public function __construct(
public readonly string $plainTextContent,
public readonly ?string $brand
) {}
}

View file

@ -1,38 +0,0 @@
<?php
namespace App\Enums\Credit;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self development()
* @method static self seo()
*/
class AccountType extends BaseEnumRoutable
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'development' => 0,
'seo' => 1
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'development' => trans('Jours de développement'),
'seo' => trans('Jours de seo')
];
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace App\Enums\Credit;
use App\Traits\Enums\BaseEnum;
enum AccountTypeEnum: int
{
use BaseEnum;
case development = 0;
case seo = 1;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::development->name => "Jours de développement",
self::seo->name => "Jours de seo",
];
}

View file

@ -1,38 +0,0 @@
<?php
namespace App\Enums\Credit;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self credit()
* @method static self debit()
*/
class BalanceOperation extends BaseEnumRoutable
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'credit' => 0,
'debit' => 1
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'credit' => trans('Créditer un compte'),
'debit' => trans('Débiter un compte')
];
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace App\Enums\Credit;
use App\Traits\Enums\BaseEnum;
enum BalanceOperationEnum: int
{
use BaseEnum;
case credit = 0;
case debit = 1;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::credit->name => "Créditer un compte",
self::debit->name => "Débiter un compte",
];
}

View file

@ -1,41 +0,0 @@
<?php
namespace App\Enums\Credit;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self pending()
* @method static self accepted()
* @method static self refused()
*/
class EstimationStatus extends BaseEnumRoutable
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'pending' => 0,
'accepted' => 1,
'refused' => 2
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'pending' => trans('En attente'),
'accepted' => trans('Acceptée'),
'refused' => trans('Refusée'),
];
}
}

View file

@ -0,0 +1,23 @@
<?php
namespace App\Enums\Credit;
use App\Traits\Enums\BaseEnum;
enum EstimationStatusEnum: int
{
use BaseEnum;
case pending = 0;
case accepted = 1;
case refused = 2;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::pending->name => "En attente",
self::accepted->name => "Acceptée",
self::refused->name => "Refusée",
];
}

View file

@ -0,0 +1,49 @@
<?php
namespace App\Enums\Credit;
use App\Traits\Enums\BaseEnum;
enum EstimationTimeEnum: int
{
use BaseEnum;
case halfHour = 0.0625;
case hour = 0.125;
case hourAndHalf = 0.1875;
case twoHours = 0.25;
case twoHoursAndHalf = 0.3125;
case threeHours = 0.375;
case threeHoursAndHalf = 0.4375;
case fourHours = 0.5;
case fourHoursAndHalf = 0.5625;
case fiveHours = 0.625;
case fiveHoursAndHalf = 0.6875;
case sixHours = 0.75;
case sixHoursAndHalf = 0.8125;
case sevenHours = 0.875;
case sevenHoursAndHalf = 0.9375;
case eightHours = 1;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::halfHour->name => "Une demi-heure",
self::hour->name => "Une heure",
self::hourAndHalf->name => "Une heure et demie",
self::twoHours->name => "Deux heures",
self::twoHoursAndHalf->name => "Deux heures et demie",
self::threeHours->name => "Trois heures",
self::twoHoursAndHalf->name => "Trois heures et demie",
self::fourHours->name => "Quatre heures",
self::fourHoursAndHalf->name => "Quatre heures et demie",
self::fiveHours->name => "Cinq heures",
self::fiveHoursAndHalf->name => "Cinq heures et demie",
self::sixHours->name => "Six heures",
self::sixHoursAndHalf->name => "Six heures et demie",
self::sevenHours->name => "Sept heures",
self::sevenHoursAndHalf->name => "Sept heures et demi",
self::eightHours->name => "Huit heures",
];
}

View file

@ -1,41 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self collectionNeeds()
* @method static self specifications()
* @method static self quotation()
* @method static self tests()
* @method static self informations()
* @method static self feedback()
*/
class FileCategory extends BaseEnumRoutable
{
protected static function values(): array
{
return [
'collectionNeeds' => 0,
'specifications' => 1,
'quotation' => 2,
'tests' => 3,
'informations' => 4,
'feedback' => 5
];
}
protected static function labels(): array
{
return [
'collectionNeeds' => trans('Recueil des besoins'),
'specifications' => trans('Cahier des charges'),
'quotation' => trans('Devis'),
'tests' => trans('Recettage'),
'informations' => trans('Informations'),
'feedback' => trans('Retours client'),
];
}
}

View file

@ -1,29 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self stringlink()
* @method static self binfile()
*/
class FileType extends BaseEnumRoutable
{
protected static function values(): array
{
return [
'stringlink' => 0,
'binfile' => 1
];
}
protected static function labels(): array
{
return [
'stringlink' => trans('Lien uri'),
'binfile' => trans('Fichier hebergé')
];
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace App\Enums\Informations;
use App\Traits\Enums\BaseEnum;
enum InfoColorsEnum: int
{
use BaseEnum;
case primary = 0;
case secondary = 1;
case success = 2;
case danger = 3;
case warning = 4;
case info = 5;
case light = 6;
case dark = 7;
/**
* Optionnal labels definition
*/
private const CLASSES = [
self::primary->name => "primary",
self::secondary->name => "secondary",
self::success->name => "success",
self::danger->name => "danger",
self::warning->name => "warning",
self::info->name => "info",
self::light->name => "light",
self::dark->name => "dark",
];
/**
* Get Class
*
* @return string
*/
public function class(): string
{
return self::CLASSES[$this->name];
}
/**
* Get enum classes
*
* @return array<string>
*/
public static function toClasses(): array
{
return self::CLASSES;
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Enums\Invoices;
use App\Traits\Enums\BaseEnum;
enum InvoiceStatusEnum: int
{
use BaseEnum;
case opened = 1;
case refused = 2;
case canceled = 3;
case archived = 4;
case awaiting_signature = 5;
case awaiting_invoicing = 6;
/**
* Optionnal labels definition.
*/
private const LABELS = [
self::opened->name => "Ouvert (nouveaux ou en cours)",
self::refused->name => "Refusé (par le client ou aucune réponse de sa part)",
self::canceled->name => "Annulé (supprimé)",
self::archived->name => "Archivé (validé et envoyé à la comptabilité)",
self::awaiting_signature->name => "En attente de signature",
self::awaiting_invoicing->name => "En attente de facturation",
];
}

View file

@ -0,0 +1,57 @@
<?php
namespace App\Enums\Invoices;
use App\Traits\Enums\BaseEnum;
enum TaskTypeEnum: int
{
use BaseEnum;
case web = 1;
case seo = 2;
case package = 3;
case arbitrary = 4;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::web->name => "Web",
self::seo->name => "SEO",
self::package->name => "Forfait",
self::arbitrary->name => "Libre",
];
/**
* Custom added prices definition
*/
private const PRICES = [
self::web->name => 600,
self::seo->name => 690,
// * Linked to packages table
self::package->name => 0,
// * Arbitrary number
self::arbitrary->name => 0,
];
/**
* Get Price
*
* @return string
*/
public function price(): string
{
return self::PRICES[$this->name];
}
/**
* Get enum prices
*
* @return array<string>
*/
public static function toPrices(): array
{
return self::PRICES;
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace App\Enums;
use App\Traits\Enums\BaseEnum;
enum ItemsPerPaginationEnum: int
{
use BaseEnum;
case five = 5;
case twelve = 12;
case twentytwo = 25;
case fifty = 50;
case onehundred = 100;
}

View file

@ -1,35 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self weak()
* @method static self stable()
* @method static self high()
* @method static self overload()
*/
class LoadLevel extends BaseEnumRoutable
{
protected static function values(): array
{
return [
'weak' => 0,
'stable' => 1,
'high' => 2,
'overload' => 3
];
}
protected static function labels(): array
{
return [
'weak' => trans('Faible'),
'stable' => trans('Stable'),
'high' => trans('Élevée'),
'overload' => trans('Surcharge')
];
}
}

View file

@ -1,47 +0,0 @@
<?php
namespace App\Enums\MacroSchedule;
use Kwaadpepper\Enum\BaseEnum;
/**
* @method static self conception()
* @method static self development()
* @method static self recipe()
* @method static self production()
* @method static self meeting()
*/
final class Activity extends BaseEnum
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'conception' => 0,
'development' => 1,
'recipe' => 2,
'production' => 3,
'meeting' => 4
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'conception' => trans('Conception / Rédaction'),
'development' => trans('Développement'),
'recipe' => trans('Mise en recette'),
'production' => trans('Mise en production'),
'meeting' => trans('Réunion')
];
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace App\Enums;
use App\Traits\Enums\BaseEnum;
enum MessageTypeEnum: int
{
use BaseEnum;
case private = 1;
case public = 2;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::private->name => "Privé",
self::public->name => "Public",
];
}

View file

@ -1,44 +0,0 @@
<?php
namespace App\Enums\Planning;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* This is an enumeration class,
* the following methods are its possible values
*
* @method static self support()
* @method static self rnd()
* @method static self dev()
* @method static self projects()
* @method static self management()
* @method static self absence()
*
*/
class ActivityType extends BaseEnumRoutable
{
public static function labels()
{
return [
'support' => trans('Support'),
'rnd' => trans('R&D'),
'dev' => trans('Développement/Facturable'),
'projects' => trans('Projets & Réunions'),
'management' => trans('Organisation management'),
'absence' => trans('Absence'),
];
}
public static function colors(): array
{
return [
'support' => '#c6e0b4',
'rnd' => '#b4c6e7',
'dev' => '#00b0f0',
'projects' => '#ffe699',
'management' => '#f4b084',
'absence' => '#aeaaaa'
];
}
}

View file

@ -1,40 +0,0 @@
<?php
namespace App\Enums\Planning;
use App\Models\Project;
use App\Models\Site;
use App\Models\Ticket;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* Décrit à quel modèle est lié
* la cellule
*
* @method static self ticket()
* \App\Models\Ticket
* @method static self site()
* \App\Models\Site
* @method static self project()
* \App\Models\Project
*/
class CellModel extends BaseEnumRoutable
{
protected static function values(): array
{
return [
'ticket' => (new Ticket())->getTable(),
'site' => (new Site())->getTable(),
'project' => (new Project())->getTable(),
];
}
protected static function labels(): array
{
return [
'ticket' => trans('Ticket'),
'site' => trans('Site'),
'project' => trans('Projet')
];
}
}

View file

@ -1,43 +0,0 @@
<?php
namespace App\Enums\Planning;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* Décrit le type d'activitée que représente
* la cellule
*
* @method static self support()
* @method static self rnd()
* @method static self dev()
* @method static self projects()
* @method static self management()
* @method static self absence()
*/
class CellType extends BaseEnumRoutable
{
protected static function values(): array
{
return [
'support' => '#c6e0b4',
'rnd' => '#b4c6e7',
'dev' => '#00b0f0',
'projects' => '#ffe699',
'management' => '#f4b084',
'absence' => '#aeaaaa'
];
}
protected static function labels(): array
{
return [
'support' => trans('Support'),
'rnd' => trans('R&D'),
'dev' => trans('Développement/Facturable'),
'projects' => trans('Projets & Réunions'),
'management' => trans('Organisation management'),
'absence' => trans('Absence'),
];
}
}

View file

@ -1,48 +0,0 @@
<?php
namespace App\Enums\Planning;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* Décrit à quel moment de la journée appartient la cellule
*
* @method static self matin1()
* @method static self matin2()
* @method static self matin3()
* @method static self matin4()
* @method static self apresmidi1()
* @method static self apresmidi2()
* @method static self apresmidi3()
* @method static self apresmidi4()
*/
class TableRow extends BaseEnumRoutable
{
protected static function values(): array
{
return [
'matin1' => 1,
'matin2' => 2,
'matin3' => 3,
'matin4' => 4,
'apresmidi1' => 5,
'apresmidi2' => 6,
'apresmidi3' => 7,
'apresmidi4' => 8,
];
}
protected static function labels(): array
{
return [
'matin1' => trans('Matin 1'),
'matin2' => trans('Matin 2'),
'matin3' => trans('Matin 3'),
'matin4' => trans('Matin 4'),
'apresmidi1' => trans('Après-midi 1'),
'apresmidi2' => trans('Après-midi 2'),
'apresmidi3' => trans('Après-midi 3'),
'apresmidi4' => trans('Après-midi 4'),
];
}
}

View file

@ -1,53 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnum;
/**
* @method static self new()
* @method static self specification()
* @method static self validated()
* @method static self development()
* @method static self recipe()
* @method static self production()
* @method static self finished()
*/
final class ProjectStatus extends BaseEnum
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'new' => 0,
'specification' => 1,
'validated' => 2,
'development' => 3,
'recipe' => 4,
'production' => 5,
'finished' => 6
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'new' => trans('Nouveau'),
'specification' => trans('Spécifications'),
'validated' => trans('Validé'),
'development' => trans('En développement'),
'recipe' => trans('En recettage'),
'production' => trans('En production'),
'finished' => trans('Terminé')
];
}
}

View file

@ -1,41 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self developper()
* @method static self admin()
* @method static self client()
*/
class Role extends BaseEnumRoutable
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'developper' => 0,
'admin' => 1,
'client' => 2
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'developper' => trans('Developpeur'),
'admin' => trans('Administrateur'),
'client' => trans('Client')
];
}
}

View file

@ -1,107 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self new()
* @method static self estimateTodo()
* @method static self estimateValidated()
* @method static self estimateDone()
* @method static self toPlan()
* @method static self planned()
* @method static self inprogress()
* @method static self waiting()
* @method static self waitingValidation()
* @method static self processed()
* @method static self recette()
* @method static self production()
* @method static self archived()
*/
class TicketStatus extends BaseEnumRoutable
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'new' => 1,
'estimateTodo' => 2,
'estimateValidated' => 3,
'toPlan' => 4,
'planned' => 5,
'inprogress' => 7,
'waiting' => 9,
'processed' => 10,
'recette' => 12,
'production' => 13,
'archived' => 15,
'estimateDone' => 16,
'waitingValidation' => 17,
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'new' => trans('Nouveau'),
'estimateTodo' => trans('Devis à faire'),
'estimateValidated' => trans('Devis validé'),
'estimateDone' => trans('Devis réalisé'),
'toPlan' => trans('À planifier'),
'planned' => trans('Planifié'),
'inprogress' => trans('En cours'),
'waiting' => trans('En attente'),
'waitingValidation' => trans('En attente validation'),
'processed' => trans('Traité'),
'recette' => trans('En recettage'),
'production' => trans('En production'),
'archived' => trans('Archivé'),
];
}
/**
* Enum classes
*
* @return array
*/
protected static function classes(): array
{
return [
'new' => 'text-danger',
'estimateTodo' => 'text-info',
'estimateValidated' => 'text-info',
'estimateDone' => 'text-info',
'toPlan' => 'text-info',
'planned' => 'text-info',
'inprogress' => 'text-dark',
'waiting' => 'text-white bg-danger',
'waitingValidation' => 'text-warning bg-danger',
'processed' => trans('Traité'),
'recette' => 'text-primary',
'production' => 'text-success',
'archived' => 'text-secondary',
];
}
/**
* @param string $attribute
* @return integer|string
*/
public function __get(string $attribute)
{
if ($attribute === 'class') {
return $this->classes()[$this->getDefinition()];
}
return parent::__get($attribute);
}
}

View file

@ -1,71 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self bug()
* @method static self evolution()
* @method static self br()
* @method static self newsletter()
*/
class TicketType extends BaseEnumRoutable
{
/**
* Enum values
*
* @return array
*/
protected static function values(): array
{
return [
'bug' => 0,
'evolution' => 1,
'br' => 2,
'newsletter' => 3
];
}
/**
* Enum labels
*
* @return array
*/
protected static function labels(): array
{
return [
'bug' => trans('Bug'),
'evolution' => trans('Évolution'),
'br' => trans('Demande BR'),
'newsletter' => trans('Demande newsletter')
];
}
/**
* Enum classes
*
* @return array
*/
protected static function classes(): array
{
return [
'bug' => 'bg-danger',
'evolution' => 'bg-success',
'br' => 'bg-primary',
'newsletter' => 'bg-warning'
];
}
/**
* @param string $attribute
* @return integer|string
*/
public function __get(string $attribute)
{
if ($attribute === 'class') {
return $this->classes()[$this->getDefinition()];
}
return parent::__get($attribute);
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace App\Enums\Tickets;
use App\Traits\Enums\BaseEnum;
enum TicketFileTypeEnum: int
{
use BaseEnum;
case png = '.png';
case jpeg = '.jpeg';
case jpg = '.jpg';
case pdf = '.pdf';
case pptx = '.pptx';
case docx = '.docx';
case xlsx = '.xlsx';
case csv = '.csv';
case svg = '.svg';
/**
* Optionnal labels definition
*/
private const LABELS = [
self::png->name => "Fichier png",
self::jpeg->name => "Fichier jpeg",
self::jpg->name => "Fichier jpg",
self::pdf->name => "Fichier pdf",
self::pptx->name => "Fichier pptx",
self::docx->name => "Fichier docx",
self::xlsx->name => "Fichier xlsx",
self::csv->name => "Fichier csv",
self::svg->name => "Fichier svg",
];
/**
* Custom added mimes type definition
*/
private const MIMETYPE = [
self::png->name => 'image/png',
self::jpeg->name => 'image/jpeg',
self::jpg->name => 'image/jpeg',
self::pdf->name => 'application/pdf',
self::pptx->name => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
self::docx->name => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
self::xlsx->name => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
self::csv->name => 'text/csv',
self::svg->name => 'image/svg+xml',
];
/**
* Get Class
*
* @return string
*/
public function mimetypes(): string
{
return self::MIMETYPE[$this->name];
}
/**
* Get enum classes
*
* @return array<string>
*/
public static function toMimetypes(): array
{
return self::MIMETYPE;
}
}

View file

@ -0,0 +1,73 @@
<?php
namespace App\Enums\Tickets;
use App\Traits\Enums\BaseEnum;
enum TicketStatusEnum: int
{
use BaseEnum;
case new = 1;
case estimateTodo = 2;
case takenInAccount = 3;
case waiting = 4;
case waitingValidation = 5;
case recette = 6;
case recetteValidated = 7;
case production = 8;
case archived = 9;
case inDev = 10;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::new->name => "Nouveau",
self::estimateTodo->name => "Étude chef(s) de projet",
self::takenInAccount->name => "À planifier",
self::waiting->name => "En attente de réponse",
self::waitingValidation->name => "En attente de validation",
self::recette->name => "En recettage",
self::recetteValidated->name => "Recettage validé",
self::production->name => "En production",
self::archived->name => "Archivé",
self::inDev->name => "En cours de développement",
];
/**
* Custom added classes definition
*/
private const CLASSES = [
self::new->name => 'text-danger',
self::estimateTodo->name => 'text-info',
self::takenInAccount->name => 'text-info',
self::waiting->name => 'text-white bg-danger',
self::waitingValidation->name => 'text-warning bg-danger',
self::recette->name => 'text-primary',
self::recetteValidated->name => 'text-success',
self::production->name => 'text-success',
self::archived->name => 'text-secondary',
self::inDev->name => 'text-discovery',
];
/**
* Get Class
*
* @return string
*/
public function class(): string
{
return self::CLASSES[$this->name];
}
/**
* Get enum classes
*
* @return array<string>
*/
public static function toClasses(): array
{
return self::CLASSES;
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace App\Enums\Tickets;
use App\Traits\Enums\BaseEnum;
enum TicketTypeEnum: int
{
use BaseEnum;
case bug = 1;
case evolution = 2;
case br = 3;
case newsletter = 4;
case qrcode = 5;
case advice = 6;
case complaints = 7;
case mailing = 8;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::bug->name => "Bug",
self::evolution->name => "Évolution",
self::br->name => "Demande BR",
self::newsletter->name => "Demande newsletter",
self::qrcode->name => "Demande de QR Code",
self::advice->name => "Conseil - Accompagnement",
self::complaints->name => "Réclamations consommateurs",
self::mailing->name => "Demande mail en masse",
];
/**
* Custom added classes definition
*/
private const CLASSES = [
self::bug->name => "bg-danger",
self::evolution->name => "bg-success",
self::br->name => "bg-primary",
self::newsletter->name => "bg-warning",
self::qrcode->name => "bg-secondary",
self::advice->name => "bg-info",
self::complaints->name => "bg-dark",
self::mailing->name => "bg-discovery",
];
/**
* Get Class
*
* @return string
*/
public function class(): string
{
return self::CLASSES[$this->name];
}
/**
* Get enum classes
*
* @return array<string>
*/
public static function toClasses(): array
{
return self::CLASSES;
}
}

View file

@ -0,0 +1,23 @@
<?php
namespace App\Enums\Users;
use App\Traits\Enums\BaseEnum;
enum RoleEnum: int
{
use BaseEnum;
case developper = 0;
case admin = 1;
case client = 2;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::developper->name => "Developpeur",
self::admin->name => "Administrateur",
self::client->name => "Client",
];
}

View file

@ -0,0 +1,30 @@
<?php
namespace App\Events;
use Domain\Models\ValueObjects\Email;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
readonly class BrevoWebhookCallReceived
{
use Dispatchable;
public function __construct(
public Email $from,
public Email $to,
public string $htmlRawContent
) {}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('default'),
];
}
}

View file

@ -1,27 +0,0 @@
<?php
namespace App\Events;
use App\Models\File;
use App\Models\User;
class FileCreated extends Loggable
{
/** @var File */
public $file;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(File $file, User $user)
{
parent::__construct($user);
$this->file = $file;
$this->message = trans(':username à crée le fichier :filename', [
'username' => $user->name,
'filename' => $file->name
]);
}
}

View file

@ -1,31 +0,0 @@
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
abstract class Loggable
{
use Dispatchable;
use SerializesModels;
/** @var User */
public $user;
public $message = '';
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
$this->message = trans(':username did someting', [
'username' => $user->name
]);
}
}

View file

@ -13,7 +13,7 @@ class NotifyAdmin
use InteractsWithSockets;
use SerializesModels;
/** @var Ticket */
/** @var \App\Models\Ticket */
public $ticket;
/** @var string */
@ -22,6 +22,8 @@ class NotifyAdmin
/**
* Create a new event instance.
*
* @param \App\Models\Ticket $ticket
* @param string $corpsMaj
* @return void
*/
public function __construct(Ticket $ticket, string $corpsMaj)

View file

@ -14,7 +14,7 @@ class NotifySubscriptions
use InteractsWithSockets;
use SerializesModels;
/** @var Ticket */
/** @var \App\Models\Ticket */
public $ticket;
/** @var string */
@ -26,6 +26,9 @@ class NotifySubscriptions
/**
* Create a new event instance.
*
* @param \App\Models\Ticket $ticket
* @param string $corpsMaj
* @param \Illuminate\Support\Collection|null $ignoreUsers
* @return void
*/
public function __construct(Ticket $ticket, string $corpsMaj, Collection $ignoreUsers = null)

View file

@ -13,7 +13,7 @@ class NotifyTicketCreator
use InteractsWithSockets;
use SerializesModels;
/** @var Ticket */
/** @var \App\Models\Ticket */
public $ticket;
/** @var string */
@ -22,6 +22,8 @@ class NotifyTicketCreator
/**
* Create a new event instance.
*
* @param \App\Models\Ticket $ticket
* @param string $corpsMaj
* @return void
*/
public function __construct(Ticket $ticket, string $corpsMaj)

View file

@ -1,27 +0,0 @@
<?php
namespace App\Events;
use App\Models\Project;
use App\Models\User;
class ProjectUpdated extends Loggable
{
/** @var Project */
public $project;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Project $project, User $user)
{
parent::__construct($user);
$this->project = $project;
$this->message = trans(':username à mis à jour projet :projectname', [
'username' => $user->name,
'projectname' => $project->name
]);
}
}

View file

@ -1,27 +0,0 @@
<?php
namespace App\Events;
use App\Models\Site;
use App\Models\User;
class SiteUpdated extends Loggable
{
/** @var Site */
public $site;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Site $site, User $user)
{
parent::__construct($user);
$this->site = $site;
$this->message = trans(':username à mis à jour site :sitename', [
'username' => $user->name,
'sitename' => $site->name
]);
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace App\Events;
use App\Models\Site;
use App\Models\Ticket;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class TicketCreated implements ShouldQueue
{
use Dispatchable;
use SerializesModels;
public function __construct(
public readonly Site $siteReceivingTicket,
public readonly Ticket $ticket,
public readonly string $byUserName
) {}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('default'),
];
}
}

View file

@ -2,6 +2,7 @@
namespace App\Events;
use App\Enums\Tickets\TicketStatusEnum;
use App\Models\Ticket;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
@ -14,27 +15,48 @@ class TicketStatusChanged
use InteractsWithSockets;
use SerializesModels;
/** @var Ticket */
/** @var \App\Models\Site */
public $ticket;
/** @var User */
/** @var \App\Models\User */
public $user;
/** @var \App\Enums\Tickets\TicketStatusEnum */
public $status;
/** @var string */
public $message;
/** @var boolean */
public $is_private;
/** @var boolean */
public $status_changed;
/**
* Create a new event instance.
*
* @param \App\Models\Ticket $ticket
* @param \App\Enums\Tickets\TicketStatusEnum $status
* @param \App\Models\User|null $user
* @param string|null $message
* @param boolean $is_private
* @param boolean $status_changed
* @return void
*/
public function __construct(Ticket $ticket, $status, User $user = null, string $message = null)
{
$this->ticket = $ticket;
$this->status = $status;
$this->user = $user;
$this->message = $message;
public function __construct(
Ticket $ticket,
TicketStatusEnum $status,
User $user = null,
string $message = null,
bool $is_private = false,
bool $status_changed = true
) {
$this->ticket = $ticket;
$this->status = $status;
$this->user = $user;
$this->message = $message;
$this->is_private = $is_private;
$this->status_changed = $status_changed;
}
}

View file

@ -2,24 +2,31 @@
namespace App\Exceptions;
use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of exception types with their corresponding custom log levels.
*
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
*/
protected $levels = [];
/**
* A list of the exception types that are not reported.
*
* @var array
* @var array<int, class-string<\Throwable>>
*/
protected $dontReport = [
];
protected $dontReport = [];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
@ -31,5 +38,10 @@ class Handler extends ExceptionHandler
*/
public function register()
{
$this->reportable(function (\Throwable $e) {
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
}
});
}
}

View file

@ -1,26 +0,0 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
public function __construct()
{
$this->middleware('guest:web');
}
}

View file

@ -1,39 +0,0 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* 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:web')->except('logout');
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Auth;
namespace App\Http\Controllers\Bo\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
@ -8,16 +8,6 @@ use Illuminate\Foundation\Auth\ConfirmsPasswords;
class ConfirmPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Confirm Password Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password confirmations and
| uses a simple trait to include the behavior. You're free to explore
| this trait and override any functions that require customization.
|
*/
use ConfirmsPasswords;
/**

View file

@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Bo\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
use SendsPasswordResetEmails;
/**
* ForgotPasswordController
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:backend');
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Bo\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* 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:backend')->except('logout');
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Auth;
namespace App\Http\Controllers\Bo\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
@ -9,16 +9,6 @@ use Illuminate\Validation\Rules\Password;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
@ -40,7 +30,7 @@ class ResetPasswordController extends Controller
'email' => 'required|email',
'password' => [
'required', 'confirmed', Password::min(8)
->mixedCase()
->mixedCase()
->letters()
->numbers()
->symbols()

View file

@ -0,0 +1,186 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Brands\StoreBrandRequest;
use App\Http\Requests\Bo\Brands\UpdateBrandRequest;
use App\Models\Brand;
use App\Models\Site;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class BrandController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $brandModels */
$brandModels = Brand::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$brandModels,
$search,
null,
'name',
);
}
$searchFields = trans('Nom');
/** Sort columns with a query */
$this->sortQuery($brandModels);
/** Custom pagination */
$brandModels = $this->customPaginate($brandModels, $request->pagination);
return view('bo.pages.brands.index', compact('brandModels', 'search', 'searchFields'));
}
/**
* Show model action.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function show(Brand $brand): \Illuminate\Contracts\View\View
{
return view('bo.pages.brands.show', ['brandModel' => $brand]);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function create(Brand $brand): \Illuminate\Contracts\View\View
{
$siteModels = Site::orderBy('name', 'ASC')->get();
return view('bo.pages.brands.create', [
'brandModel' => $brand,
'siteModels' => $siteModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\StoreBrandRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreBrandRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$brand = new Brand();
$brand->fill($request->safe()->except('sites'));
if ($brand->saveOrFail()) {
$brand->updateSites($brand);
return redirect()
->route('bo.brands.edit', $brand)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.brands'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.brands'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function edit(Brand $brand): \Illuminate\Contracts\View\View
{
$siteModels = Site::orderBy('name', 'ASC')->get();
return view('bo.pages.brands.edit', [
'brandModel' => $brand,
'siteModels' => $siteModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\UpdateBrandRequest $request
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateBrandRequest $request, Brand $brand): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $brand) {
$brand->fill($request->safe()->except(['sites']));
$brand->updateSites($brand);
if ($brand->saveOrFail()) {
return redirect()
->route('bo.brands.edit', $brand)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.brands'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.brands'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Brand $brand): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($brand) {
if (count($brand->accounts)) {
return redirect()
->route('bo.brands.index')
->with('error', __(
':model n\'as pas pu être supprimé car elle est encore associée avec des Sites.',
['model' => Str::singular(trans('models.classes.brands'))]
));
} else {
$brand->deleteSites($brand);
if ($brand->deleteOrFail()) {
return redirect()
->route('bo.brands.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.brands'))]
));
}
return redirect()
->back()
->with('error', __(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.brands'))]
));
} //end if
});
}
}

View file

@ -0,0 +1,58 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Events\BrevoWebhookCallReceived;
use App\Http\Requests\Bo\BrevoWebhookRequest;
use Domain\Models\ValueObjects\Email;
use Psr\Log\LoggerInterface;
use Illuminate\Routing\Controller as BaseController;
use \Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
class BrevoWebhookController extends BaseController
{
public function __construct(
private readonly LoggerInterface $logger,
private readonly Dispatcher $dispatcher
) {}
public function webhookCallReceived(BrevoWebhookRequest $request): JsonResponse
{
$fromEmail = $request->getFromAddress();
$toEmail = $request->getToAddress();
$formContent = $request->getRawHtmlBody();
if (!$this->isFromLdc($fromEmail)) {
$this->logger->warning(
'Received a brevo webhook call from a non ldc email.',
[
'from' => $fromEmail,
'to' => $toEmail,
'content' => base64_encode($formContent)
]
);
return response()->json(
['ok' => false],
Response::HTTP_BAD_REQUEST
);
}
$this->dispatcher->dispatch(
new BrevoWebhookCallReceived(
from: $fromEmail,
to: $toEmail,
htmlRawContent: $formContent,
)
);
return response()->json(['ok' => true]);
}
private function isFromLdc(Email $email): bool
{
return substr(strrchr($email->value, "@"), 1) === 'ldc.fr';
}
}

View file

@ -0,0 +1,166 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Companies\StoreCompanyRequest;
use App\Http\Requests\Bo\Companies\UpdateCompanyRequest;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class CompanyController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $companyModels */
$companyModels = Company::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$companyModels,
$search,
null,
'name'
);
}
$searchFields = trans('Nom');
/** Sort columns with a query */
$this->sortQuery($companyModels);
/** Custom pagination */
$companyModels = $this->customPaginate($companyModels, $request->pagination);
return view('bo.pages.companies.index', compact('companyModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Company $company
* @return \Illuminate\Contracts\View\View
*/
public function create(Company $company): \Illuminate\Contracts\View\View
{
return view('bo.pages.companies.create', [
'companyModel' => $company,
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Companies\StoreCompanyRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreCompanyRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$company = new Company();
$company->fill($request->validated());
if ($company->saveOrFail()) {
return redirect()
->route('bo.companies.edit', $company)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.companies'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.companies'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Company $company
* @return \Illuminate\Contracts\View\View
*/
public function edit(Company $company): \Illuminate\Contracts\View\View
{
return view('bo.pages.companies.edit', [
'companyModel' => $company
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Companies\UpdateCompanyRequest $request
* @param \App\Models\Company $company
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateCompanyRequest $request, Company $company): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $company) {
$company->fill($request->validated());
if ($company->saveOrFail()) {
return redirect()
->route('bo.companies.edit', $company)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.companies'))]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.companies'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Company $company
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Company $company): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($company) {
if (count($company->invoices()->get()->toArray())) {
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_deleted_relationship',
[
'model' => Str::singular(trans('models.classes.companies')),
'relationship' => trans('models.classes.invoices')
]
));
}
if ($company->deleteOrFail()) {
return redirect()
->route('bo.companies.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.companies'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.companies'))]
));
});
}
}

View file

@ -0,0 +1,107 @@
<?php
namespace App\Http\Controllers\Bo\Credit;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\CreditAccounts\StoreCreditAccountRequest;
use App\Models\Brand;
use App\Models\Credit\Account;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class AccountController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \App\Models\User $user */
$user = auth()->user();
if (!$user->isAdmin()) {
$brandModels = $user->brands()->pluck('id');
} else {
$brandModels = $request->brand ?? Brand::all()->pluck('id');
}
/** @var \Illuminate\Database\Eloquent\Builder $credit_accountModels */
$credit_accountModels = Account::query()->whereIn('brand_id', $brandModels);
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$credit_accountModels,
$search,
null,
'label',
'balance',
);
}
$searchFields = trans('Label, solde');
/** Sort columns with a query */
$this->sortQuery($credit_accountModels);
/** Custom pagination */
$credit_accountModels = $this->customPaginate($credit_accountModels, $request->pagination);
return view('bo.pages.credit_accounts.index', compact(
'credit_accountModels',
'brandModels',
'search',
'searchFields'
));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Brand $brand
* @param \App\Models\Account $account
* @return \Illuminate\Contracts\View\View
*/
public function create(Brand $brand, Account $account): \Illuminate\Contracts\View\View
{
return view('bo.pages.credit_accounts.create', [
'brandModel' => $brand,
'credit_accountModel' => $account
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Models\Brand $brand
* @param \App\Http\Requests\Bo\CreditAccounts\StoreCreditAccountRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Brand $brand, StoreCreditAccountRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($brand, $request) {
$credit_accountModel = new Account();
$credit_accountModel->brand_id = $brand->id;
$credit_accountModel->fill($request->validated());
if ($credit_accountModel->saveOrFail()) {
return redirect()
->route('bo.brands.credit_accounts.index', $brand)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.accounts'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.accounts'))]
));
});
}
}

View file

@ -0,0 +1,108 @@
<?php
namespace App\Http\Controllers\Bo\Credit;
use App\Enums\Credit\BalanceOperationEnum;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\CreditLogs\StoreCreditLogRequest;
use App\Models\Brand;
use App\Models\Credit\Account;
use App\Models\Credit\CreditLog;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class CreditLogController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
$brandModel = $request->brand;
$credit_accountModel = $request->account;
/** @var \Illuminate\Database\Eloquent\Builder $credit_logModels */
$credit_logModels = CreditLog::query()->where('credit_account_id', $credit_accountModel->id);
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$credit_logModels,
$search,
null,
'amount',
);
}
$searchFields = trans('Montant');
/** Sort columns with a query */
$this->sortQuery($credit_logModels);
/** Custom pagination */
$credit_logModels = $this->customPaginate($credit_logModels, $request->pagination);
return view('bo.pages.credit_logs.index', compact(
'credit_logModels',
'credit_accountModel',
'brandModel',
'search',
'searchFields'
));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Brand $brand
* @param \App\Models\Account $account
* @return \Illuminate\Contracts\View\View
*/
public function create(Brand $brand, Account $account): \Illuminate\Contracts\View\View
{
return view('bo.pages.credit_logs.create', [
'brandModel' => $brand,
'credit_accountModel' => $account
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Models\Brand $brand
* @param \App\Models\Account $account
* @param \App\Http\Requests\Bo\CreditLogs\StoreCreditLogRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(
Brand $brand,
Account $account,
StoreCreditLogRequest $request
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($brand, $account, $request) {
$credit_logModel = new CreditLog();
$credit_logModel->credit_account_id = $request->account->id;
$credit_logModel->type = BalanceOperationEnum::credit;
$credit_logModel->fill($request->validated());
if ($credit_logModel->saveOrFail()) {
return redirect()
->route('bo.brands.credit_accounts.index', ['brand' => $brand, 'account' => $account])
->with('success', trans(
':model a été crédité',
['model' => Str::singular(trans('models.classes.accounts'))]
));
}
return redirect()
->back()
->with('error', trans(
':model ne peut être crédité',
['model' => Str::singular(trans('models.classes.accounts'))]
));
});
}
}

View file

@ -1,15 +1,15 @@
<?php
namespace App\Http\Controllers\Credit;
namespace App\Http\Controllers\Bo\Credit;
use App\Enums\Credit\EstimationStatus;
use App\Enums\TicketStatus;
use App\Enums\Credit\EstimationStatusEnum;
use App\Enums\Tickets\TicketStatusEnum;
use App\Events\NotifyAdmin;
use App\Events\NotifySubscriptions;
use App\Events\TicketStatusChanged;
use App\Http\Controllers\Controller;
use App\Http\Requests\Credit\AnswerEstimateRequest;
use App\Http\Requests\Credit\CreateEstimateRequest;
use App\Http\Requests\Bo\Credit\AnswerEstimateRequest;
use App\Http\Requests\Bo\Credit\CreateEstimateRequest;
use App\Models\Credit\Estimation;
use App\Models\Ticket;
use Illuminate\Support\Facades\DB;
@ -32,8 +32,8 @@ class EstimationController extends Controller
/**
* Create Ticket estimation
*
* @param \App\Http\Requests\Credit\CreateEstimateRequest $request
* @param \App\Models\Ticket $ticket
* @param \App\Http\Requests\Bo\Credit\CreateEstimateRequest $request
* @param \App\Models\Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function estimateSubmit(CreateEstimateRequest $request, Ticket $ticket)
@ -44,19 +44,19 @@ class EstimationController extends Controller
$estimate = new Estimation($request->validated());
$estimate->ticket()->associate($ticket);
$estimate->estimator()->associate($user);
$ticket->status = TicketStatus::waitingValidation();
$ticket->status = TicketStatusEnum::waitingValidation;
$ticket->saveQuietly();
if ($estimate->saveOrFail()) {
$message = sprintf(
'<b>%s</b> a modifié le statut en <b>%s</b>, Une estimation de %s jours à été ajoutée',
$user->name,
$ticket->status->label,
$ticket->status->label(),
\number_format(\floatval($request->amount), 1, ',', '')
);
event(new TicketStatusChanged($ticket, $ticket->status, $user));
event(new NotifySubscriptions($ticket, $message));
event(new NotifyAdmin($ticket, $message));
return response()->redirectToRoute('ticket.show', $ticket)
return response()->redirectToRoute('bo.ticket.show', $ticket)
->with('info', trans('L\'estimation à bien été ajouté'));
}
return \back();
@ -66,8 +66,8 @@ class EstimationController extends Controller
/**
* Answer ticket estimation
*
* @param \App\Http\Requests\Credit\AnswerEstimateRequest $request
* @param \App\Models\Ticket $ticket
* @param \App\Http\Requests\Bo\Credit\AnswerEstimateRequest $request
* @param \App\Models\Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function estimatePendingSubmit(AnswerEstimateRequest $request, Ticket $ticket)
@ -77,11 +77,11 @@ class EstimationController extends Controller
/** @var \App\Models\Credit\Estimation */
$estimation = $ticket->estimation;
if ($request->answer) {
$ticket->status = TicketStatus::toPlan();
$estimation->status = EstimationStatus::accepted();
$ticket->status = TicketStatusEnum::takenInAccount;
$estimation->status = EstimationStatusEnum::accepted;
} else {
$ticket->status = TicketStatus::archived();
$estimation->status = EstimationStatus::refused();
$ticket->status = TicketStatusEnum::archived;
$estimation->status = EstimationStatusEnum::refused;
}
$estimation->validator()->associate($user);
if ($estimation->saveOrFail() and $ticket->saveOrFail()) {
@ -89,14 +89,34 @@ class EstimationController extends Controller
'Une réponse à été fourni par %s pour l\'estimation du ticket n°%d : %s',
$user->name,
$ticket->id,
$estimation->status->label
$estimation->status->label()
);
event(new TicketStatusChanged($ticket, $ticket->status, $user));
event(new NotifySubscriptions($ticket, $message));
event(new NotifyAdmin($ticket, $message));
return response()->redirectToRoute('ticket.show', $ticket)
return response()->redirectToRoute('bo.ticket.show', $ticket)
->with('info', trans('Votre réponse à été enregistrée'));
}
return \back();
}
/**
* Handle submit and cancel an estimate on ticket
*
* @param \App\Models\Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function estimateCancelSubmit(Ticket $ticket)
{
$this->authorize('cancelEstimate', $ticket);
/** @var \App\Models\Credit\Estimation */
$estimation = $ticket->estimation;
$ticket->status = TicketStatusEnum::estimateTodo;
if ($estimation->deleteOrFail() and $ticket->saveOrFail()) {
return response()->redirectToRoute('bo.ticket.show', $ticket)
->with('info', trans('L\'estimation a été supprimée.'));
}
return \back();
}
}

View file

@ -0,0 +1,158 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Informations\StoreInformationRequest;
use App\Http\Requests\Bo\Informations\UpdateInformationRequest;
use App\Models\Information;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class InformationController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $informationModels */
$informationModels = Information::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$informationModels,
$search,
null,
'title',
'message'
);
}
$searchFields = trans('Titre, message');
/** Sort columns with a query */
$this->sortQuery($informationModels);
/** Custom pagination */
$informationModels = $this->customPaginate($informationModels, $request->pagination);
return view('bo.pages.informations.index', compact('informationModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Information $information
* @return \Illuminate\Contracts\View\View
*/
public function create(Information $information): \Illuminate\Contracts\View\View
{
return view('bo.pages.informations.create', [
'informationModel' => $information
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Informations\StoreInformationRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreInformationRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$information = new Information();
$information->fill($request->validated());
if ($information->saveOrFail()) {
return redirect()
->route('bo.informations.edit', $information)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.informations'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.informations'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Information $information
* @return \Illuminate\Contracts\View\View
*/
public function edit(Information $information): \Illuminate\Contracts\View\View
{
return view('bo.pages.informations.edit', [
'informationModel' => $information,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Informations\UpdateInformationRequest $request
* @param \App\Models\Information $information
* @return \Illuminate\Http\RedirectResponse
* @ignore phpcs:disable Generic.Files.LineLength.TooLong
*/
public function update(UpdateInformationRequest $request, Information $information): \Illuminate\Http\RedirectResponse
{
// phpcs:enable
return DB::transaction(function () use ($request, $information) {
$information->fill($request->validated());
if ($information->saveOrFail()) {
return redirect()
->route('bo.informations.edit', $information)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.informations'))]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.informations'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Information $information
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Information $information): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($information) {
if ($information->deleteOrFail()) {
return redirect()
->route('bo.informations.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.informations'))]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.informations'))]
));
});
}
}

View file

@ -0,0 +1,227 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Enums\Invoices\InvoiceStatusEnum;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Invoices\StoreInvoiceRequest;
use App\Http\Requests\Bo\Invoices\UpdateInvoiceRequest;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\Package;
use App\Models\Site;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
class InvoiceController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
// If no sorting is requested, apply the default orderByDesc.
/** @var \Illuminate\Database\Eloquent\Builder $invoiceModels */
$invoiceModels = (!request()->query('sort_col') && !request()->query('sort_way'))
? Invoice::query()->orderByDesc('created_at')
: Invoice::query();
$status = intval($request->status);
switch ($status) {
case InvoiceStatusEnum::awaiting_signature->value:
$invoiceModels->whereNotNull('sent_client_date')->whereNull('signed_date');
break;
case InvoiceStatusEnum::awaiting_invoicing->value:
$invoiceModels->whereNotNull('sent_client_date')->whereNotNull('signed_date')->whereNull('sent_accounting_date');
break;
default:
if ($status !== 0) {
$invoiceModels->where('status', $status);
}
break;
}
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$invoiceModels,
$search,
null,
'firstname',
'lastname',
'ref',
'site_id',
);
}
$searchFields = trans('Nom, Prénom, Référence, Site');
/** Sort columns with a query */
$this->sortQuery($invoiceModels);
/** Custom pagination */
$invoiceModels = $this->customPaginate($invoiceModels, $request->pagination);
return view('bo.pages.invoices.index', compact('invoiceModels', 'search', 'searchFields', 'status'));
}
/**
* Show model action.
*
* @param \App\Models\Invoice $invoice
* @return \Illuminate\Contracts\View\View
*/
public function show(Invoice $invoice): \Illuminate\Contracts\View\View
{
return view('bo.pages.invoices.show', ['invoiceModel' => $invoice]);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Invoice $invoice
* @return \Illuminate\Contracts\View\View
*/
public function create(Invoice $invoice): \Illuminate\Contracts\View\View
{
$packageModels = Package::where('published', true)->get();
$taskRowModel = Invoice::getTaskStructure();
$siteModels = Site::orderBy('name', 'ASC')->get();
$companyModels = Company::get();
return view('bo.pages.invoices.create', [
'invoiceModel' => $invoice,
'taskRowModel' => $taskRowModel,
'packageModels' => $packageModels,
'siteModels' => $siteModels,
'companyModels' => $companyModels,
'invoiceStatusArray' => $invoice->getInvoiceStatusArray($invoice),
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Invoices\StoreInvoiceRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreInvoiceRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$invoice = new Invoice();
$invoice->fill($request->validated());
if ($invoice->saveOrFail()) {
return redirect()
->route('bo.invoices.edit', $invoice)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.invoices'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.invoices'))]
));
});
}
/**
* Edit model action.
*
* @param Invoice $invoice
* @return \Illuminate\Contracts\View\View
*/
public function edit(Invoice $invoice): \Illuminate\Contracts\View\View
{
$packageModels = Package::get();
$taskRowModel = Invoice::getTaskStructure();
$siteModels = Site::orderBy('name', 'ASC')->get();
$companyModels = Company::get();
return view('bo.pages.invoices.edit', [
'invoiceModel' => $invoice,
'taskRowModel' => $taskRowModel,
'packageModels' => $packageModels,
'siteModels' => $siteModels,
'companyModels' => $companyModels,
'invoiceStatusArray' => $invoice->getInvoiceStatusArray($invoice),
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Invoices\UpdateInvoiceRequest $request
* @param \App\Models\Invoice $invoice
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateInvoiceRequest $request, Invoice $invoice): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $invoice) {
$invoice->fill(($invoice->status->value === InvoiceStatusEnum::opened->value) ? $request->validated() : []);
if ($invoice->saveOrFail()) {
return redirect()
->route('bo.invoices.edit', $invoice)
->with('success', __(
'crud.messages.has_been_updated',
['model' => __('models.classes.invoices')]
));
} //end if
return redirect()
->back()
->with('error', __(
'crud.messages.cannot_be_updated',
['model' => __('models.classes.invoices')]
));
});
}
/**
* Download Invoice.
*
* @param \App\Models\Invoice $invoice
* @return \Illuminate\Http\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
public function download(Invoice $invoice)
{
if (Gate::allows('isAdmin')) {
return $invoice->generateInvoice()
->stream(Str::slug(trans('Devis :appname :date - ref :ref', [
'appname' => config('app.name'),
'date' =>
$invoice->created_at !== $invoice->updated_at ?
$invoice->updated_at->isoFormat('YYYY-MM-DD') :
$invoice->created_at->isoFormat('YYYY-MM-DD'),
'ref' => $invoice->ref,
])) . '.pdf');
}
return redirect()->route('bo.invoices.index')
->with('error', __('crud.messages.cannot_be_updated', [
'model' => __('models.classes.invoices')
]));
}
/**
* Get a paginate resource.
*
* @param \Illuminate\Http\Request $request
* @return Illuminate\Http\JsonResponse
*/
public function jsonPaginate(Request $request): \Illuminate\Http\JsonResponse
{
$model = $request->targetModel;
return DB::transaction(function () use ($model) {
$models = $model::query()->orderBy('name', 'ASC')->paginate(12);
return \response()->json($models ?? 500);
});
}
}

View file

@ -0,0 +1,157 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Labels\StoreLabelRequest;
use App\Http\Requests\Bo\Labels\UpdateLabelRequest;
use App\Models\Label;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class LabelController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $labelModels */
$labelModels = Label::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$labelModels,
$search,
null,
'name'
);
}
$searchFields = trans('Nom');
/** Sort columns with a query */
$this->sortQuery($labelModels);
/** Custom pagination */
$labelModels = $this->customPaginate($labelModels, $request->pagination);
return view('bo.pages.labels.index', compact('labelModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Label $label
* @return \Illuminate\Contracts\View\View
*/
public function create(Label $label): \Illuminate\Contracts\View\View
{
return view('bo.pages.labels.create', [
'labelModel' => $label
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Labels\StoreLabelRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreLabelRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$label = new Label();
$label->fill($request->validated());
if ($label->saveOrFail()) {
return redirect()
->route('bo.labels.edit', $label)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.labels'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.labels'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Label $label
* @return \Illuminate\Contracts\View\View
*/
public function edit(Label $label): \Illuminate\Contracts\View\View
{
return view('bo.pages.labels.edit', [
'labelModel' => $label,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Labels\UpdateLabelRequest $request
* @param \App\Models\Label $label
* @return \Illuminate\Http\RedirectResponse
* @ignore phpcs:disable Generic.Files.LineLength.TooLong
*/
public function update(UpdateLabelRequest $request, Label $label): \Illuminate\Http\RedirectResponse
{
// phpcs:enable
return DB::transaction(function () use ($request, $label) {
$label->fill($request->validated());
if ($label->saveOrFail()) {
return redirect()
->route('bo.labels.edit', $label)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.labels'))]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.labels'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Label $label
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Label $label): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($label) {
if ($label->deleteOrFail()) {
return redirect()
->route('bo.labels.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.labels'))]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.labels'))]
));
});
}
}

View file

@ -0,0 +1,177 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Packages\StorePackageRequest;
use App\Http\Requests\Bo\Packages\UpdatePackageRequest;
use App\Models\Package;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class PackageController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $packageModels */
$packageModels = Package::query();
$status = $request->status;
if ($status === null) {
$packageModels->where('published', true);
} elseif ($status === '0') {
$packageModels->where('published', false);
} elseif ($status === '1') {
$packageModels->where('published', true);
}
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$packageModels,
$search,
null,
'name',
'amount'
);
}
$searchFields = trans('Nom, Montant');
/** Sort columns with a query */
$this->sortQuery($packageModels);
/** Custom pagination */
$packageModels = $this->customPaginate($packageModels, $request->pagination);
return view('bo.pages.packages.index', compact('packageModels', 'search', 'searchFields', 'status'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Package $package
* @return \Illuminate\Contracts\View\View
*/
public function create(Package $package): \Illuminate\Contracts\View\View
{
return view('bo.pages.packages.create', [
'packageModel' => $package,
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Packages\StorePackageRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StorePackageRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$package = new Package();
$package->fill($request->validated());
if ($package->saveOrFail()) {
return redirect()
->route('bo.packages.edit', $package)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.packages'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.packages'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Package $package
* @return \Illuminate\Contracts\View\View
*/
public function edit(Package $package): \Illuminate\Contracts\View\View
{
return view('bo.pages.packages.edit', [
'packageModel' => $package,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Packages\UpdatePackageRequest $request
* @param \App\Models\Package $package
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdatePackageRequest $request, Package $package): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $package) {
$package->fill($request->validated());
if ($package->saveOrFail()) {
return redirect()
->route('bo.packages.edit', $package)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.packages'))]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.packages'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Package $package
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Package $package): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($package) {
if ($package->deleteOrFail()) {
return redirect()
->route('bo.packages.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.packages'))]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.packages'))]
));
});
}
/**
* Change model published.
*
* @param \App\Models\Package $package
* @return \Illuminate\Http\RedirectResponse
*/
public function changePublished(Package $package)
{
$package->update(['published' => !$package->getOriginal('published')]);
return redirect()->back()->with('success', trans(__('crud.messages.publish_status_saved')));
}
}

View file

@ -0,0 +1,204 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Sites\StoreSiteRequest;
use App\Http\Requests\Bo\Sites\UpdateSiteRequest;
use App\Lib\Helpers\ToolboxHelper;
use App\Models\Site;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class SiteController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \App\Models\User $user */
$user = Auth::user();
if ($user->isAdmin()) {
/** @var \Illuminate\Database\Eloquent\Builder $siteModels */
$siteModels = Site::query()->with(['invoices', 'tickets']);
} else {
/** @var \Illuminate\Database\Eloquent\Builder $siteModels */
$siteModels = Site::whereHas('users', function (\Illuminate\Database\Eloquent\Builder $query) use ($user) {
$query->where('id', $user->id)->with(['invoices', 'tickets']);
});
}
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$siteModels,
$search,
null,
'name',
);
}
$searchFields = trans('Nom');
/** Sort columns with a query */
$this->sortQuery($siteModels);
/** Custom pagination */
$siteModels = $this->customPaginate($siteModels, $request->pagination);
return view('bo.pages.sites.index', compact('siteModels', 'search', 'searchFields'));
}
/**
* Show model action.
*
* @param \App\Models\Site $site
* @return \Illuminate\Contracts\View\View
*/
public function show(Site $site): \Illuminate\Contracts\View\View
{
return view('bo.pages.sites.show', ['siteModel' => $site]);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Site $site
* @return \Illuminate\Contracts\View\View
*/
public function create(Site $site): \Illuminate\Contracts\View\View
{
$userModels = User::orderBy('name', 'ASC')->get();
return view('bo.pages.sites.create', [
'siteModel' => $site,
'userModels' => $userModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Sites\StoreSiteRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreSiteRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$site = new Site();
$site->fill($request->validated());
if ($site->saveOrFail()) {
$site->users()->attach(collect($request->validated('users'))->pluck('id'));
return redirect()
->route('bo.sites.edit', $site)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.sites'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.sites'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Site $site
* @return \Illuminate\Contracts\View\View
*/
public function edit(Site $site): \Illuminate\Contracts\View\View
{
$userModels = User::orderBy('name', 'ASC')->get();
return view('bo.pages.sites.edit', [
'siteModel' => $site,
'userModels' => $userModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Sites\UpdateSiteRequest $request
* @param \App\Models\Site $site
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateSiteRequest $request, Site $site): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $site) {
$site->fill($request->validated());
$site->users()->sync(collect($request->validated('users'))->pluck('id'));
if ($site->saveOrFail()) {
return redirect()
->route('bo.sites.edit', $site)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.sites'))]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.sites'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Site $site
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Site $site): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($site) {
if ($site->deleteOrFail()) {
$site->users()->detach();
return redirect()
->route('bo.sites.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.sites'))]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.sites'))]
));
});
}
/**
* Get a paginate resource.
*
* @param \Illuminate\Http\Request $request
* @return Illuminate\Http\JsonResponse
*/
public function jsonPaginate(Request $request): \Illuminate\Http\JsonResponse
{
return DB::transaction(function () use ($request) {
$model = $request->targetModel;
$search = $request->search;
$models = $model::where("name", "LIKE", "%{$search}%")->orderBy("name", "ASC");
return ToolboxHelper::jsonPaginate($this->customPaginate($models, $request->pagination));
});
}
}

View file

@ -0,0 +1,933 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Models\Site;
use App\Models\User;
use App\Models\Ticket;
use App\Mail\NewTicket;
use App\Models\Message;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Jobs\UpdateIssueLabels;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Support\Facades\DB;
use App\Events\NotifySubscriptions;
use App\Events\TicketStatusChanged;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\LinkTicket;
use Illuminate\Support\Facades\Mail;
use App\Enums\Tickets\TicketTypeEnum;
use App\Http\Requests\Bo\SortTickets;
use App\Http\Requests\Bo\StoreTicket;
use App\Http\Requests\Bo\UpdateTicket;
use App\Lib\Helpers\FileStorageHelper;
use App\Enums\Tickets\TicketStatusEnum;
use App\Events\TicketCreated;
use App\Http\Requests\Bo\CreateMessage;
use App\Http\Requests\Bo\UpdateMessage;
use Illuminate\Support\Facades\Session;
use GrahamCampbell\GitLab\Facades\GitLab;
use Illuminate\Database\Eloquent\Builder;
use App\Http\Requests\Bo\ChangeTicketStatus;
use App\Http\Requests\Bo\UpdateChangeOrderRequest;
use App\Http\Requests\Bo\AssignTicketToUserRequest;
use App\Http\Requests\Bo\UpdateTicketPriorityRequest;
use Illuminate\Contracts\Events\Dispatcher;
class TicketController extends Controller
{
/**
* TicketController
*/
public function __construct(
public readonly Dispatcher $dispatcher
) {
parent::__construct();
$this->authorizeResource(Ticket::class, 'ticket');
}
/**
* Tickets List
*
* @param SortTickets $request
* @return \Illuminate\Http\JsonResponse|\Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(SortTickets $request)
{
// * Handle Ajax
if ($request->ajax()) {
$tickets = Ticket::with(['user', 'assignedUser']);
if ($request->s) {
$tickets = $tickets->where('text', 'LIKE', "%$request->s%")
->orWhere('id', $request->s)
->orWhereHas('user', function ($q) use ($request) {
$q->where('name', 'LIKE', "%$request->s%");
});
}
/** @var \Illuminate/Pagination/LengthAwarePaginator $tickets */
$tickets = $tickets->paginate();
return \response()->json($tickets->getCollection()->map(function (Ticket $ticket) {
return [
'label' => sprintf(
'Ticket %d (%s): %s',
$ticket->id,
$ticket->user ? $ticket->user->name : trans('Utilisateur supprimé'),
Str::limit(\preg_replace('/[[:cntrl:]]+/', '', $ticket->text), 35)
),
'value' => $ticket->id
];
}));
} //end if
/** @var \App\Models\User */
$user = auth()->user();
$tickets = Ticket::with(['site', 'labels']);
if (!$user->isAdmin()) {
$tickets->whereHas('site', function ($q) use ($user) {
$q->whereHas('users', function ($q) use ($user) {
$q->whereId($user->id);
});
});
$tickets->where('is_internal', false);
} else {
$tickets->has('site');
}
$tickets->where(
'status',
($request->st == TicketStatusEnum::archived->value) ? '=' : '<>',
TicketStatusEnum::archived
);
if (!$user->isAdmin() && $user->sites->count() === 1) {
$request->merge([
'pr' => $user->sites->first()->id,
]);
}
$tickets = $this->filterTickets($tickets, $request);
$tickets = $this->searchTicket($tickets, $request);
/** Sort columns with a query */
$this->sortQuery($tickets);
/** Custom pagination */
$tickets = $this->customPaginate($tickets, $request->pagination);
$sites = Site::select('id', 'name')->orderBy('name')->get();
$status = Arr::sort(TicketStatusEnum::cases(), function (TicketStatusEnum $value) {
return $value->label();
});
$types = Arr::sort(TicketTypeEnum::cases(), function (TicketTypeEnum $value) {
return $value->label();
});
return view('bo.pages.tickets.index', compact('tickets', 'sites', 'status', 'types'));
}
/**
* Show Ticket
*
* @param Request $request
* @param Ticket $ticket
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function show(Request $request, Ticket $ticket)
{
if ($request->ajax()) {
return \response()->json([
'label' => $ticket->formatName($ticket),
'value' => $ticket->id
]);
}
/** @var \App\Models\User */
$user = auth()->user();
if (!$user->can('update', $ticket)) {
abort(403);
}
if ($ticket->is_internal && !$user->can('changeInternalStatus', $ticket)) {
abort(403);
}
$messages = $ticket->messages()->orderBy('created_at', 'DESC')->get();
$isSubscribed = (bool)$ticket->subscriptions()->where('user_id', $user->id)->count();
return view('bo.pages.tickets.show', [
'ticket' => $ticket,
'messages' => $messages,
'isSubscribed' => $isSubscribed
]);
}
/**
* Show create Form
*
* @return \Illuminate\Http\RedirectResponse
*/
public function create()
{
/** @var \App\Models\User */
$user = auth()->user();
if ($user->isAdmin()) {
$sites = Site::orderBy('name')->get();
} else {
$sites = $user->sites;
}
if (!count($sites)) {
return redirect()->route('bo.sites.create')
->with('warning', trans('Vous devez tout d\'abord créer un site pour y ajouter un ticket'));
}
return view('bo.pages.tickets.create', compact('sites'));
}
/**
* Create ticket
*
* @param StoreTicket $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreTicket $request)
{
try {
return DB::transaction(function () use ($request) {
/** @var \App\Models\Site */
$site = Site::findOrFail($request->site_id);
/** @var \App\Models\User */
$user = auth()->user();
$ticket = new Ticket($request->validated());
/** @var array<\Illuminate\Http\UploadedFile> */
$fileTickets = $request->file_tickets ?? [];
if (count($fileTickets) > 0) {
foreach ($fileTickets as $key => $file) {
if ($key === 0) {
$ticket->file = FileStorageHelper::storeFile($ticket, $file);
} else {
$fileNumber = 'file' . $key + 1;
$ticket->$fileNumber = FileStorageHelper::storeFile($ticket, $file);
}
}
}
$ticket->user()->associate($user);
$ticket->site()->associate($site);
$ticket->saveOrFail();
if ($request->labels) {
$ticket->labels()->sync($request->labels);
}
$user->subscriptions()->toggle($ticket->id);
$this->dispatcher->dispatch(new TicketCreated(
siteReceivingTicket: $site,
ticket: $ticket,
byUserName: $user->name
));
return redirect()->route('bo.ticket.show', $ticket)
->with('success', trans('Ticket enregistré !'));
});
} catch (\ErrorException $e) {
report($e);
Session::flash('error', trans('Une erreur est survenue'));
} //end try
return \back();
}
/**
* Show update form
*
* @param Ticket $ticket
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function edit(Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
if ($user->isAdmin()) {
$sites = Site::orderBy('name')->get();
} else {
$sites = $user->sites;
}
return view('bo.pages.tickets.edit', compact('ticket', 'sites'));
}
/**
* Update Model
*
* @param UpdateTicket $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateTicket $request, Ticket $ticket)
{
$ticket->fill($request->validated());
try {
return DB::transaction(function () use ($request, $ticket) {
/** @var \App\Models\Site */
$site = Site::findOrFail($request->site_id);
/** @var null|array<\Illuminate\Http\UploadedFile> */
$fileTickets = $request->file_tickets;
if (isset($fileTickets) && count($fileTickets) > 0) {
foreach ($fileTickets as $key => $file) {
if ($key === 0) {
$ticket->file = FileStorageHelper::storeFile($ticket, $file);
} else {
$fileNumber = 'file' . $key + 1;
$ticket->$fileNumber = FileStorageHelper::storeFile($ticket, $file);
}
}
}
$ticket->labels()->sync($request->labels);
$ticket->site()->associate($site);
$ticket->saveOrFail();
return redirect()->route('bo.ticket.edit', $ticket->id)
->with('success', 'Modifications enregistrées !');
});
} catch (\ErrorException $e) {
report($e);
Session::flash('error', trans('Une erreur est survenue'));
} //end try
return \back();
}
/**
* Change ticket Status
*
* @param ChangeTicketStatus $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function changeStatus(ChangeTicketStatus $request, Ticket $ticket)
{
if ($ticket->gitlab_issue) {
\dispatch(new UpdateIssueLabels($ticket, $request->status));
}
$ticket->fill($request->validated());
$ticket->saveOrFail();
return back()
->with('warning', trans('Le status à été modifié'));
}
/**
* Add a new Message to the Ticket
*
* @param CreateMessage $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function createMessage(CreateMessage $request, Ticket $ticket)
{
try {
return DB::transaction(function () use ($request, $ticket) {
/** @var \Illuminate\Http\UploadedFile|null */
$filesMessage = $request->file_messages;
$message = new Message($request->validated());
$message->user()->associate(auth()->user());
$message->ticket()->associate($ticket);
/** @var \App\Models\User */
$user = auth()->user();
// Subscribe to ticket.
if ($request->subscribe) {
$user->subscriptions()->syncWithoutDetaching([$ticket->id]);
} else {
$user->subscriptions()->detach($ticket->id);
}
// Store files if any.
if (isset($filesMessage) and $filesMessage) {
foreach ($filesMessage as $key => $singleFile) {
if ($key === 0) {
$message->file = FileStorageHelper::storeFile($message, $singleFile);
$message->saveOrFail();
} else {
$fileNumber = 'file' . $key + 1;
$message->$fileNumber = FileStorageHelper::storeFile($message, $singleFile);
$message->saveOrFail();
}
}
}
$message->saveOrFail();
return back()
->with('success', trans('Votre message à été ajouté'));
}, 5);
} catch (\ErrorException $e) {
report($e);
Session::flash('error', trans('Une erreur est survenue'));
} //end try
return back();
}
/**
* Update Message
*
* @param UpdateMessage $request
* @param Ticket $ticket
* @param Message $message
* @return \Illuminate\Http\RedirectResponse
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
*/
public function updateMessage(UpdateMessage $request, Ticket $ticket, Message $message)
{
$message->message = $request->message;
$message->saveOrFail();
return back()
->with('success', trans('Votre message à bien été modifié'));
}
/**
* Change ticket status to archived
*
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function setToArchive(Ticket $ticket)
{
$ticket->status = TicketStatusEnum::archived;
$ticket->saveOrFail();
return redirect()->route('bo.ticket.index')
->with('warning', trans('Le ticket est archivé'));
}
/**
* Subscribe to ticket
*
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function subscribe(Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
$user->subscriptions()->toggle($ticket->id);
if ($user->subscriptions()->where('ticket_id', $ticket->id)->exists()) {
return back()
->with('success', trans('Vous avez été inscrit'));
}
return back()->with('warning', trans('Vous avez été désinscrit'));
}
/**
* Reopen ticket
*
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function reopen(Ticket $ticket)
{
$message = trans(':ticketName à réouvert le ticket n°:ticketNumber', [
'ticketName' => $ticket->user->name,
'ticketNumber' => $ticket->id,
]);
/** @var \App\Enums\Tickets\TicketStatusEnum */
$oldStatus = $ticket->status;
$ticket->status = TicketStatusEnum::new;
$ticket->saveQuietly();
event(new TicketStatusChanged($ticket, $oldStatus, null, $message, false, false));
event(new NotifySubscriptions($ticket, $message, collect([$ticket->user])));
/** @var \App\Models\User */
$user = auth()->user();
$user->subscriptions()->toggle($ticket->id);
return back()->with('warning', trans('Votre ticket à été réouvert.'));
}
/**
* Assign ticket to user ticket
*
* @param AssignTicketToUserRequest $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function assignTo(AssignTicketToUserRequest $request, Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
/** @var \App\Models\User|null */
if ($assignedUser = User::whereId($request->assign)->first()) {
$message = trans(':admin a assigné le ticket n°:ticketNumber à :assignedAdmin', [
'admin' => $user->name,
'ticketNumber' => $ticket->id,
'assignedAdmin' => $assignedUser->name,
]);
$ticket->assignedUser()->associate($assignedUser);
} else {
$message = trans(
':admin a modifié l\'assignation du ticket n°:ticketNumber, il n\'est plus assigné à quelqu\'un.',
[
'admin' => $user->name,
'ticketNumber' => $ticket->id,
]
);
$ticket->assignedUser()->dissociate();
}
$ticket->saveQuietly();
/** @var \App\Enums\Tickets\TicketStatusEnum */
$oldStatus = $ticket->status;
// * Notification systeme doit etre privée.
event(new TicketStatusChanged($ticket, $oldStatus, null, $message, true, false));
event(new NotifySubscriptions($ticket, $message, collect([$ticket->user])));
/** @var \App\Models\User */
$user = auth()->user();
$user->subscriptions()->toggle($ticket->id);
if ($assignedUser) {
return back()->with('info', trans('Le ticket à été assigné à :assignedUser', [
'assignedUser' => $assignedUser->name
]));
}
return back()->with('info', trans('Le ticket n\'est plus assigné à personne'));
}
/**
* Link two tickets.
*
* @param LinkTicket $request
* @param Ticket $ticket
*
* @return \Illuminate\Http\RedirectResponse
*/
public function linkTicket(LinkTicket $request, Ticket $ticket)
{
$linkedTicket = Ticket::findOrFail($request->validated())->first();
if ($ticket->site_id !== $linkedTicket->site_id) {
return back()->with('error', trans('Le ticket que vous avez renseigné ne fait pas partie du même site.'));
}
if (!$ticket->linkedTickets()->where('linked_ticket_id', $linkedTicket->id)->exists()) {
$ticket->linkedTickets()->attach($linkedTicket->id);
$linkedTicket->linkedTickets()->attach($ticket->id);
return back()->with('success', trans('Les tickets ont été liés avec succès.'));
}
return back()->with('error', trans('Les tickets sont déjà liés ensemble.'));
}
/**
* Unlink two tickets.
*
* @param Ticket $ticket
* @param Ticket $linkedTicket
*
* @return \Illuminate\Http\RedirectResponse
*/
public function unlinkTicket(Ticket $ticket, Ticket $linkedTicket)
{
$ticket->linkedTickets()->detach($linkedTicket->id);
$linkedTicket->linkedTickets()->detach($ticket->id);
return back()->with('warning', trans('Le lien entre les tickets à été supprimé.'));
}
// * PRIVATES
/**
* Filter Tickets request constructor
*
* @param Builder $tickets
* @param Request $request
* @return Builder
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
private function filterTickets(Builder $tickets, Request $request): Builder
{
//phpcs:enable
if ($request->rst) {
Session::remove('tickets.ass');
Session::remove('tickets.st');
Session::remove('tickets.pr');
Session::remove('tickets.ty');
Session::remove('tickets.sort_col');
Session::remove('tickets.sort_way');
Session::remove('tickets.or');
Session::remove('tickets.search');
}
if ($request->assr) {
Session::remove('tickets.ass');
}
if ($request->prs) {
Session::remove('tickets.pr');
}
if ($request->sts) {
Session::remove('tickets.st');
}
if ($request->tys) {
Session::remove('tickets.ty');
}
if ($request->sort_col) {
Session::put('tickets.sort_col', $request->sort_col);
}
if ($request->sort_way) {
Session::put('tickets.sort_way', $request->sort_way);
}
if ($request->ord) {
Session::remove('tickets.or');
}
if ($request->pr) {
Session::put('tickets.pr', $request->pr);
}
if ($request->st) {
Session::put('tickets.st', $request->st);
}
if ($request->ty) {
Session::put('tickets.ty', $request->ty);
}
if ($request->ass) {
Session::put('tickets.ass', $request->ass);
}
if (Session::has('tickets.or')) {
Session::remove('tickets.ass');
Session::remove('tickets.st');
Session::remove('tickets.ty');
Session::remove('tickets.sort_col');
Session::remove('tickets.sort_way');
Session::remove('tickets.search');
}
if ($request->or && Session::has('tickets.pr')) {
Session::put('tickets.or', $request->or);
}
Session::save();
if (Session::has('tickets.pr')) {
$tickets->where('site_id', Session::get('tickets.pr'));
}
if (Session::has('tickets.ass')) {
$tickets->whereHas('assignedUser', function ($q) {
$q->whereId(Session::get('tickets.ass'));
});
}
if (Session::has('tickets.st')) {
$tickets->where('status', Session::get('tickets.st'));
}
if (Session::has('tickets.ty')) {
$tickets->where('type', Session::get('tickets.ty'));
}
if (Session::has('tickets.or')) {
$tickets->orderBy('order', 'ASC');
}
if (
Session::has('tickets.sort_col') and
Session::has('tickets.sort_way') and
in_array(Session::get('tickets.sort_col'), [
'type',
'title',
'assigned_to',
'date_mep',
'created_at',
'created_by'
])
) {
$tickets->orderBy(
Session::get('tickets.sort_col'),
Session::get('tickets.sort_way')
);
} else {
$tickets->orderBy('last_activity', 'DESC');
}
return $tickets;
}
/**
* Search ticket sql request constructor
*
* @param Builder $tickets
* @param Request $request
* @return Builder
*/
private function searchTicket(Builder $tickets, Request $request): Builder
{
if ($request->exists('search')) {
if (empty($request->search)) {
Session::remove('tickets.search');
} else {
Session::put('tickets.search', $request->search);
}
}
if (!Session::has('tickets.search')) {
return $tickets;
}
return $this->searchQuery($tickets, Session::get('tickets.search'), function ($q) {
$words = explode(' ', Session::get('tickets.search'));
if (\is_array($words)) {
foreach ($words as $word) {
if (!strlen($word)) {
continue;
}
$s = collect(TicketStatusEnum::cases())->filter(function (TicketStatusEnum $t) use ($word) {
return Str::slug($t->label()) === Str::slug($word);
})->map(function (TicketStatusEnum $ticket) {
return $ticket->value;
});
$t = collect(TicketTypeEnum::cases())->filter(function (TicketTypeEnum $s) use ($word) {
return Str::slug($s->label()) === Str::slug($word);
})->map(function (TicketTypeEnum $ticket) {
return $ticket->value;
});
$q->orWhere('id', $word)
->orWhereIn('status', $s)
->orWhereIn('type', $t)
->orWhereHas('user', function ($q) use ($word) {
$q->where('name', 'LIKE', "%$word%");
});
} //end foreach
} //end if
}, 'text', 'title', 'file', 'file2', 'file3', 'file4', 'file5');
}
/**
* Get a paginate resource.
*
* @param \Illuminate\Http\Request $request
* @return Illuminate\Http\JsonResponse
*/
public function jsonPaginate(Request $request): \Illuminate\Http\JsonResponse
{
return DB::transaction(function () use ($request) {
$model = $request->targetModel;
$search = $request->search;
// * Handle Ajax
$tickets = $model::with(['user', 'assignedUser']);
if ($search) {
$tickets = $tickets->where('text', 'LIKE', "%$search%")
->orWhere('id', $search)
->orWhereHas('user', function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%");
})
->orderBy("id", "ASC");
}
return ToolboxHelper::jsonPaginate(
$this->customPaginate($tickets, $request->pagination),
'formatName'
);
});
}
/**
* Create a gitlab issue from a ticket.
*
* @param \App\Models\Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function createGitlabIssue(Ticket $ticket)
{
$userGitlabId = auth()->user()->gitlab_id;
$gitlabRepoId = $ticket->site->gitlab_project_id;
if (GitLab::projects()->show($gitlabRepoId)['archived']) {
return back()->with('error', \trans("Ce projet GitLab est archivé et ne peut pas être utilisé."));
}
$description = \sprintf("%s<br>", $ticket->text);
$cLabel = match ($ticket->type) {
TicketTypeEnum::bug => 'c-bug,g-to-dispatch',
TicketTypeEnum::evolution,
TicketTypeEnum::mailing => 'c-feature',
TicketTypeEnum::newsletter => 'c-feature,g-to-estimate',
};
$assigneeId = match ($ticket->type) {
TicketTypeEnum::bug => $userGitlabId,
TicketTypeEnum::evolution,
TicketTypeEnum::mailing,
TicketTypeEnum::newsletter => $ticket->site->projectManager?->gitlab_id
};
try {
foreach ($ticket->getFiles() as $key => $file) {
if (!\is_null($file)) {
$uploadedFile = GitLab::projects()->uploadFile($gitlabRepoId, $file);
$description .= $this->formatGitlabFiles($ticket, $uploadedFile, $key + 1);
}
}
$data = [
'title' => sprintf(
'ts-%s : %s',
$ticket->id,
$ticket->title
),
'description' => $description,
'labels' => \implode(",", [
'c-support',
$cLabel
]),
];
if ($assigneeId) {
$data['assignee_id'] = $assigneeId;
}
$issue = GitLab::issues()->create($gitlabRepoId, $data);
} catch (\Exception $e) {
\report($e);
return back()->with('error', \trans("Une erreur est survenue"));
} catch (\Throwable $e) {
\report($e);
return back()->with('error', \trans("Une erreur est survenue"));
} //end try
$ticket->gitlab_issue = $issue['web_url'];
$ticket->save();
return back()->with(
'success',
trans("L'issue a été créée sur Gitlab.")
);
}
/**
* Format files for Gitlab issues
*
* @param \App\Models\Ticket $ticket
* @param array $uploadedFile
* @param integer $fileNb
* @return string
*/
private function formatGitlabFiles(Ticket $ticket, array $uploadedFile, int $fileNb)
{
if (Str::endsWith($ticket->file, ['jpg', 'png', 'jpeg', 'pptx', 'docx', 'xslx', 'csv', 'svg'])) {
$file = \sprintf(
"![Fichier joint %d](%s)",
$fileNb,
$uploadedFile['url']
);
} else {
$file = \sprintf(
'<a href="%s" target="_blank">%s</a>',
$uploadedFile['url'],
__('Lien vers le fichier'),
);
}
return \sprintf("<br><br> Fichier %d : <br>%s<br>", $fileNb, $file);
}
/**
* Change order.
*
* @param \App\Http\Requests\Bo\UpdateChangeOrderRequest $request
* @param mixed ...$params
* @return \Illuminate\Http\RedirectResponse
* @throws \RuntimeException Si le nom du parametre de la route ne correspond pas au params utilisé.
*/
public function changeOrder(UpdateChangeOrderRequest $request, mixed ...$params): \Illuminate\Http\RedirectResponse
{
$paramNames = collect(request()->route()->parameterNames);
$className = Str::of($paramNames->get($paramNames->count() - 2))->lower()->studly();
$className = "\\App\\Models\\{$className}";
$model = Arr::get($params, $paramNames->count() - 2);
if (!class_exists($className)) {
throw new \RuntimeException("The {$className} class doesn't exist.");
}
if (!\is_object($model)) {
throw new \RuntimeException("The second last param isn't an object.");
}
if (get_class($model) !== (string)Str::of($className)->replaceStart('\\', '')) {
throw new \RuntimeException("The {$className} doesn't match second last binded param.");
}
/** @var \Illuminate\Database\Eloquent\Model|null */
$model = $className::query()->where($model->getRouteKeyName(), $model->getRouteKey())->first();
if (!$model) {
return back()->with('error', trans('crud.messages.order_not_changed'));
}
return DB::transaction(function () use ($request, $className, $model) {
/** @var \Illuminate\Support\Collection $models */
$models = $className::query()
->orderBy('order', 'ASC')
->where('site_id', $model->site_id)
->where('status', '!=', TicketStatusEnum::archived)
->where('id', '!=', $model->getKey())
->where('order', $request->direction ? '<' : '>', $model->order)
->get();
/** @var \Illuminate\Database\Eloquent\Model|null $tmp */
$tmp = $request->direction ? $models->last() : $models->first();
if (!$tmp) {
return back()->with('error', trans('crud.messages.order_not_changed'));
}
$newOrder = $tmp->getOriginal('order');
$tmp->update(['order' => $model->getOriginal('order')]);
$model->update(['order' => $newOrder]);
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
});
}
/**
* Update ticket priority.
*
* @param UpdateTicketPriorityRequest $request
* @param Ticket $ticket
* @return void
*/
public function changePriority(UpdateTicketPriorityRequest $request, Ticket $ticket)
{
$newPriority = $request->validated('priority');
return DB::transaction(function () use ($ticket, $newPriority) {
// Update all tickets who will be moved with this priority update.
$request = Ticket::query()
->where('site_id', $ticket->site_id)
->whereNot('status', TicketStatusEnum::archived)
->whereNot('id', $ticket->id)
->whereBetween('order', [min($ticket->order, $newPriority), max($ticket->order, $newPriority)]);
$ticket->order < $newPriority ? $request->decrement('order', 1) : $request->increment('order', 1);
// Update the ticket.
$ticket->order = $newPriority;
if (!$ticket->saveOrFail()) {
return back()->with('error', trans('crud.messages.order_not_changed'));
};
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
});
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\TicketTypes\UpdateTicketTypeRequest;
use App\Models\Ticket\TicketType;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class TicketTypeController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $ticketTypeModels */
$ticketTypeModels = TicketType::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$ticketTypeModels,
$search,
null,
'type',
);
}
$searchFields = trans('Type');
/** Sort columns with a query */
$this->sortQuery($ticketTypeModels);
/** Custom pagination */
$ticketTypeModels = $this->customPaginate($ticketTypeModels, $request->pagination);
return view('bo.pages.ticket_types.index', compact('ticketTypeModels', 'search', 'searchFields'));
}
/**
* Show the form for editing the specified resource.
*
* @param App\Models\Ticket\TicketType $ticketType
* @return \Illuminate\Contracts\View\View
* @ignore phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function edit(TicketType $ticketType): \Illuminate\Contracts\View\View
{
return view('bo.pages.ticket_types.edit', ['ticketTypeModel' => $ticketType]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\TicketTypes\UpdateTicketTypeRequest $request
* @param \App\Models\Ticket\TicketType $ticketType
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateTicketTypeRequest $request, TicketType $ticketType): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $ticketType) {
$ticketType->fill($request->validated());
if ($ticketType->saveOrFail()) {
return redirect()->route('bo.ticket_types.edit', $ticketType->id)
->with('success', __('crud.messages.has_been_updated', [
'model' => trans_choice('models.classes.ticket_types', 1)
]));
}
return redirect()->route('bo.ticket_types.edit', $ticketType->id)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => trans_choice('models.classes.ticket_types', 1)
]));
});
}
}

View file

@ -0,0 +1,232 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Models\Site;
use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Users\StoreUserRequest;
use App\Http\Requests\Bo\Users\UpdateUserRequest;
use App\Http\Controllers\Bo\Auth\ForgotPasswordController;
use App\Http\Requests\Bo\Users\FavouriteSiteRequest;
class UserController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $userModels */
$userModels = User::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$userModels,
$search,
null,
'name',
'email'
);
}
$searchFields = trans('Label, email');
/** Sort columns with a query */
$this->sortQuery($userModels);
/** Custom pagination */
$userModels = $this->customPaginate($userModels, $request->pagination);
return view('bo.pages.users.index', compact('userModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\User $user
* @return \Illuminate\Contracts\View\View
*/
public function create(User $user): \Illuminate\Contracts\View\View
{
$siteModels = Site::orderBy('name', 'ASC')->get();
return view('bo.pages.users.create', [
'userModel' => $user,
'siteModels' => $siteModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Users\StoreUserRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreUserRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$user = User::query()->onlyTrashed()->where('email', $request->validated('email'))->first() ?? new User();
$user->fill($request->safe()->except('sites'));
$user->deleted_at = null;
if ($user->saveOrFail()) {
$user->sites()->attach(collect($request->validated('sites'))->pluck('id'));
return redirect()
->route('bo.users.edit', $user)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.users'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.users'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\User $user
* @return \Illuminate\Contracts\View\View
*/
public function edit(User $user): \Illuminate\Contracts\View\View
{
$siteModels = Site::orderBy('name', 'ASC')->get();
return view('bo.pages.users.edit', [
'userModel' => $user,
'siteModels' => $siteModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Users\UpdateUserRequest $request
* @param \App\Models\User $user
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateUserRequest $request, User $user): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $user) {
$user->fill($request->safe()->except(['sites']));
$user->sites()->sync(collect($request->validated('sites'))->pluck('id'));
if ($user->saveOrFail()) {
return redirect()
->route('bo.users.edit', $user)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.users'))]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.users'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\User $user
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(User $user): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($user) {
if ($user->deleteOrFail()) {
$user->sites()->detach();
return redirect()
->route('bo.users.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.users'))]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.users'))]
));
});
}
/**
* Password reset form
*
* @return \Illuminate\Contracts\View\View
*/
public function settings(): \Illuminate\Contracts\View\View
{
return view('bo.pages.users.settings');
}
/**
* Favourite site submit
*
* @param \App\Http\Requests\Bo\Users\FavouriteSiteRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function favouriteSiteSubmit(FavouriteSiteRequest $request): \Illuminate\Http\RedirectResponse
{
/** @var \App\Models\User */
$user = auth()->user();
try {
$user->favourite_site_id = $request->favourite_site_id;
$user->saveOrFail();
return redirect()->back()->with("success", trans('crud.messages.favourite_site_changed'));
} catch (\Exception $e) {
\report($e);
return redirect()->back()->with('error', trans('crud.messages.favourite_site_not_changed'));
} catch (\Throwable $e) {
\report($e);
return redirect()->back()->with('error', trans('crud.messages.favourite_site_not_changed'));
}
}
/**
* Password reset submit
*
* @return \Illuminate\Http\RedirectResponse
*/
public function passwordResetSubmit(): \Illuminate\Http\RedirectResponse
{
/** @var \App\Models\User */
$user = auth()->user();
$request = new Request(['email' => $user->email]);
return app(ForgotPasswordController::class)->sendResetLinkEmail($request);
}
/**
* Get february last day date of the year
*
* @param integer $year
* @return integer 28 or 29
*/
private function getLastDayFebruary(int $year): int
{
if ((is_int($year / 4) && !is_int($year / 100)) || is_int($year / 400)) {
return 29;
}
return 28;
}
}

View file

@ -1,51 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Brand;
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class BrandController extends Controller
{
use CrudController {
__construct as __CrudConstructor;
index as crudIndex;
}
/** @var Account */
public static $modelClass = Brand::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
/**
* ProjectController
*/
public function __construct()
{
parent::__construct();
$this->__CrudConstructor();
$this->authorizeResource(Brand::class, 'brand');
}
/**
* Crud index view
*
* @param \Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(CrudIndexRequest $request)
{
/** @var \Illuminate\View\View */
$view = $this->crudIndex($request);
if ($request->ajax()) {
return $view;
}
return view('brands.index', $view->getData());
}
}

View file

@ -2,15 +2,20 @@
namespace App\Http\Controllers;
use App\Enums\Tickets\TicketStatusEnum;
use App\Models\Ticket;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use App\Enums\TicketStatus;
use App\Models\Ticket;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Str;
class Controller extends BaseController
{
@ -37,19 +42,17 @@ class Controller extends BaseController
55,
];
$ticketsNew = Ticket::where('status', TicketStatus::new());
$ticketsWaiting = Ticket::where('status', TicketStatus::waiting());
$ticketsNew = Ticket::where('status', TicketStatusEnum::new);
$ticketsWaiting = Ticket::where('status', TicketStatusEnum::waiting);
$ticketsInProgress = Ticket::whereNotIn(
'status',
[
TicketStatus::new(),
TicketStatus::estimateTodo(),
TicketStatus::estimateValidated(),
TicketStatus::toPlan(),
TicketStatus::planned(),
TicketStatus::waiting(),
TicketStatus::production(),
TicketStatus::archived()
TicketStatusEnum::new,
TicketStatusEnum::estimateTodo,
TicketStatusEnum::waiting,
TicketStatusEnum::production,
TicketStatusEnum::archived,
TicketStatusEnum::takenInAccount
]
);
@ -73,12 +76,13 @@ class Controller extends BaseController
* Build Search query on specified fields
* splitting search into words or using whole sentence
*
* @param 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 Builder
* @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,
@ -109,27 +113,135 @@ class Controller extends BaseController
/**
* Build query search on all fields
*
* @param Builder $query
* @param string $search
* @param array $fields
* @return Builder
* @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
{
private function searchOnFields(
Builder $query,
string $search,
array $fields
): \Illuminate\Database\Eloquent\Builder {
$table = $query->getModel()->getTable();
foreach ($fields as $f) {
$f = str_replace('?', '\?', $f);
if (is_array($f)) {
foreach ($fields as $field) {
$field = str_replace('?', '\?', $field);
if (is_array($field)) {
$query->orWhereRaw(
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($f)->map(function ($q) use ($table) {
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($field)->map(function ($q) use ($table) {
return "`$table`.`$q`";
})->implode(', \' \', ')),
["%$search%"]
['%' . htmlspecialchars($search) . '%']
);
} else {
$query->orWhereRaw("UPPER(`$table`.`$f`) LIKE UPPER(?)", ["%$search%"]);
return $query;
}
// Get models woth enum's label.
if (is_array($this->getSearchValue($query, $search, $field))) {
foreach ($this->getSearchValue($query, $search, $field) as $array) {
$query->orWhereRaw(
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
['%' . htmlspecialchars($array->value) . '%']
);
}
return $query;
}
// Get models with relation's name/label.
if (Str::endsWith($field, '_id')) {
$query->orWhereHas(Str::remove('_id', $field), function ($queryRelation) use ($field, $search) {
if (Schema::hasColumn(Str::remove('_id', $field) . 's', 'name')) {
$queryRelation->where('name', 'like', '%' . $search . '%');
} elseif (Schema::hasColumn(Str::remove('_id', $field) . 's', 'label')) {
$queryRelation->where('label', 'like', '%' . $search . '%');
}
});
return $query;
}
$query->orWhereRaw(
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
['%' . htmlspecialchars($this->getSearchValue($query, $search, $field)) . '%']
);
} //end foreach
return $query;
}
/**
* Get the search value (on string or Enum).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param string $field
* @return string|array
*/
protected function getSearchValue(Builder $query, string $search, string $field): string|array
{
$cast = $query->getModel()->getCasts()[$field] ?? null;
if (
count($query->getModel()->getCasts()) and // Check if the model has casts.
$cast and // Check if there is cast about specific field.
enum_exists($cast) // Check if the cast is an enum.
) {
/** @var \App\Traits\Enums $cast */
// @phpstan-ignore-next-line
$cases = collect($cast::toArray());
$enum = $cases->filter(function ($item) use ($search) {
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label));
});
return $enum->toArray();
} else {
return $search;
}
}
/**
* 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 &&
request()->sort_way &&
Schema::hasColumn($table, request()->sort_col) &&
(!isset($ignore) || (isset($ignore) && !in_array(request()->sort_col, $ignore)))
) {
$query = $query->orderBy("$table." . request()->sort_col, request()->sort_way);
}
return $query;
}
/**
* Customize pagination with cache or config (default).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer|null $pagination
* @return \Illuminate\Pagination\LengthAwarePaginator
*/
protected function customPaginate(Builder $query, $pagination): LengthAwarePaginator
{
if ($pagination) {
Cache::put('pagination', $pagination);
};
$query = $query->paginate(
(Cache::get('pagination')) ? intval(Cache::get('pagination')) : config('pagination.default')
);
return $query;
}
}

View file

@ -1,118 +0,0 @@
<?php
namespace App\Http\Controllers\Credit;
use App\Enums\Credit\BalanceOperation;
use App\Http\Controllers\Controller;
use App\Http\Requests\Credit\AddCreditToAccountRequest;
use App\Models\Brand;
use App\Models\Credit\Account;
use App\Models\Credit\CreditLog;
use Illuminate\Database\Eloquent\Builder;
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class AccountController extends Controller
{
use CrudController {
__construct as __CrudConstructor;
index as crudIndex;
}
/** @var Account */
public static $modelClass = Account::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
/**
* Index query middleware
*
* @param Builder $query
* @return Builder
*/
public function indexQuery(Builder $query): Builder
{
/** @var \App\Models\User */
$user = auth()->user();
if (!$user->isAdmin()) {
// Show only users brand(s) accounts.
$brands = $user->sites()->with('brand')->get()->pluck('brand')
->filter(function ($v) {
return !\is_null($v);
});
return $query->whereHas('brand', function ($q) use ($brands) {
$q->whereIn('id', $brands->pluck('id'));
});
}
return $query;
}
/**
* Crud index view
*
* @param \Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(CrudIndexRequest $request)
{
/** @var \Illuminate\View\View */
$view = $this->crudIndex($request);
if ($request->ajax()) {
return $view;
}
return view('accounts.index', $view->getData());
}
/**
* Before store model middleware
*
* @param Account $model
* @return void
*/
public function storeModel(Account &$model)
{
$model->brand()->associate(\request()->brand);
}
/**
* Credit
*
* @param \App\Models\Brand $brand
* @param \App\Models\Account $account
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
*/
public function credit(Brand $brand, Account $account)
{
return view('accounts.credit', compact('brand', 'account'));
}
/**
* Credit Account
*
* @param \App\Http\Requests\Credit\AddCreditToAccountRequest $request
* @param \App\Models\Brand $brand
* @param \App\Models\Account $account
* @return \Illuminate\Http\RedirectResponse
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
*/
public function creditSubmit(AddCreditToAccountRequest $request, Brand $brand, Account $account)
{
$log = new CreditLog();
$log->account()->associate($account);
$log->type = BalanceOperation::credit();
$log->amount = \strval($request->amount);
if ($log->saveOrFail()) {
return \response()->redirectToRoute('brands.credit_accounts.index', $brand)
->with('info', trans('Le compte à bien été crédité'));
}
return back();
}
}

View file

@ -1,55 +0,0 @@
<?php
namespace App\Http\Controllers\Credit;
use App\Http\Controllers\Controller;
use App\Models\Credit\CreditLog;
use Illuminate\Database\Eloquent\Builder;
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class CreditLogController extends Controller
{
use CrudController {
__construct as __CrudConstructor;
index as crudIndex;
}
/** @var CreditLog */
public static $modelClass = CreditLog::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
/**
* Index query middleware
*
* @param Builder $query
* @return Builder
*/
public function indexQuery(Builder $query): Builder
{
$query->orderBy('created_at', 'DESC');
return $query;
}
/**
* Crud index view
*
* @param \Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(CrudIndexRequest $request)
{
/** @var \Illuminate\View\View */
$view = $this->crudIndex($request);
if ($request->ajax()) {
return $view;
}
return view('credit_logs.index', $view->getData());
}
}

View file

@ -1,83 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\File;
use Illuminate\Database\Eloquent\Builder;
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class FileController extends Controller
{
use CrudController {
index as crudIndex;
create as crudCreate;
}
/** @var File */
public static $modelClass = File::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
/**
* Index query middleware
*
* @param Builder $query
* @return Builder
*/
public function indexQuery(Builder $query): Builder
{
$parent = request()->site ?? request()->project;
if ($parent) {
$query->whereHasMorph('parent', [get_class($parent)], function ($q) use ($parent) {
return $q->whereId($parent->id);
});
}
return $query;
}
/**
* Crud index view
*
* @param \Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(CrudIndexRequest $request)
{
/** @var \Illuminate\View\View */
$view = $this->crudIndex($request);
if ($request->ajax()) {
return $view;
}
return view('files.index', $view->getData());
}
/**
* Crud create view
*
* @param \Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function create(CrudIndexRequest $request)
{
/** @var \Illuminate\View\View */
$view = $this->crudCreate($request);
return view('files.create', $view->getData());
}
/**
* Before store model middleware
*
* @param \App\Models\File $file
* @return void
*/
public function storeModel(File &$file)
{
$file->parent()->associate(request()->site ?? request()->project);
}
}

View file

@ -1,21 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\File;
use Parsedown;
class HomeController extends Controller
{
/**
* Show Home page
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function home()
{
$Parsedown = new Parsedown();
$changelog = $Parsedown->text(File::get(\app_path('../CHANGELOG.md')));
return view('home', ['changelog' => $changelog]);
}
}

View file

@ -1,21 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Label;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class LabelController extends Controller
{
use CrudController;
/** @var Label */
public static $modelClass = Label::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
}

View file

@ -1,54 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Log;
use Illuminate\Database\Eloquent\Builder;
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class LogController extends Controller
{
use CrudController {
index as crudIndex;
}
/** @var Log */
public static $modelClass = Log::class;
public static $layout = 'layout.app';
public function indexQuery(Builder $query): Builder
{
$parent = request()->site ?? request()->project;
if ($parent) {
$query->whereHasMorph('parent', [get_class($parent)], function ($q) use ($parent) {
return $q->whereId($parent->id);
});
}
return $query;
}
public function index(CrudIndexRequest $request)
{
// Autosort
if (!$request->sort_col and !$request->sort_way) {
$request->merge([
'sort_col' => 'created_at',
'sort_way' => 'desc',
]);
}
/** @var \Illuminate\View\View */
$view = $this->crudIndex($request);
if ($request->ajax()) {
return $view;
}
return view('logs.index', $view->getData());
}
public function storeModel(Log &$log)
{
$log->parent()->associate(request()->site ?? request()->project);
}
}

View file

@ -1,87 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\MacroSchedule\Marker;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\View;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class MarkerController extends Controller
{
use CrudController;
/** @var \App\Models\MacroSchedule\Marker */
public static $modelClass = Marker::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
/**
* Crud index Hook
*
* @param Builder $query
* @return Builder
*/
public function indexQuery(Builder $query): Builder
{
$parent = request()->project;
if ($parent) {
$query->whereHas('project', function ($q) use ($parent) {
return $q->whereId($parent->id);
});
}
return $query;
}
/**
* Show create page middleware
*
* @return void
*/
public function createModel()
{
$this->shareLabelsToView();
}
/**
* Show edit model middleware
*
* @param Model $model
* @return void
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function editModel(Model &$model)
{
$this->shareLabelsToView();
}
/**
* Before store model middleware
*
* @param \App\Models\MacroSchedule\Marker $marker
* @return void
*/
public function storeModel(Marker &$marker)
{
$marker->project()->associate(request()->project);
}
/**
* Share Marker labels to view
*
* @return void
*/
protected function shareLabelsToView()
{
View::share('markerLabels', Cache::remember('markers_labels', 20, function () {
return Marker::pluck('label');
}));
}
}

View file

@ -1,71 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Project;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class ProjectController extends Controller
{
use CrudController {
__construct as __CrudConstructor;
index as crudIndex;
show as crudShow;
}
/**
* ProjectController
*/
public function __construct()
{
parent::__construct();
$this->__CrudConstructor();
$this->authorizeResource(Project::class, 'project');
}
/** @var \App\Models\Project */
public static $modelClass = Project::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
/**
* Crud index view
*
* @param \Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(CrudIndexRequest $request)
{
/** @var \Illuminate\View\View */
$view = $this->crudIndex($request);
if ($request->ajax()) {
return $view;
}
return view('projects.index', $view->getData());
}
/**
* Crud show view
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Project $model
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function show(Request $request, Project $model)
{
/** @var \Illuminate\View\View */
$view = $this->crudshow($request, $model);
if ($view instanceof JsonResponse) {
return $view;
}
return view('projects.show', $view->getData());
}
}

View file

@ -1,172 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Enums\Role;
use App\Http\Requests\StoreScheduleRequest;
use App\Models\Schedule;
use App\Models\User;
use Illuminate\Http\Request;
use Carbon\CarbonImmutable;
/**
* Alternate planner for Dev Team
*
* @author Olivier Legat <olivier.legat@ldc.fr>
*
*/
class ScheduleController extends Controller
{
/**
* ScheduleController
*/
public function __construct()
{
parent::__construct();
$this->middleware('is-admin');
}
public function index(Request $request)
{
$date = CarbonImmutable::now()->startOfWeek();
$nbweeks = config('schedules.shownWeeks');
if ($request->p) {
$date = CarbonImmutable::createFromFormat('d/m/Y', $request->p)->startOfWeek();
}
$dbusers = User::where('role', Role::developper())->get();
$users = [];
foreach ($dbusers as $user) {
$users[$user->id] = ['name' => $user->name];
}
$schedules = Schedule::whereDate('date', '>=', $date)
->whereDate('date', '<=', $date->addDays($nbweeks * 7 - 1))
->orderBy('user_id')
->orderBy('slot')
->orderBy('date')
->get();
$arSchedules = array();
$prevUserId = null;
$prevDate = null;
$prevSlot = null;
foreach ($schedules as $schedule) {
$id_lie = array('label' => null, 'value' => null);
if (!is_null($schedule->model_lie)) {
if (isset($schedule->relatedModel->name)) {
$id_lie = array('label' => $schedule->relatedModel->name, 'value' => $schedule->id_lie);
} else {
$id_lie = array('label' => 'Ticket ' . $schedule->id_lie, 'value' => $schedule->id_lie);
}
$model_lie = $schedule->model_lie;
} else {
$model_lie = array('label' => null, 'value' => null);
}
if ($prevUserId != $schedule->user_id) {
// nouveau user
$arSchedules[$schedule->user_id] = array(
$schedule->slot => array(
$schedule->date->format('d/m/Y') => array(
'id' => $schedule->id,
'type' => $schedule->activity,
'text' => $schedule->description,
'id_lie' => $id_lie,
// $schedule->id_lie,
'model_lie' => $model_lie,
),
)
);
} else {
// same user
if ($prevSlot != $schedule->slot) {
// new slot
$arSchedules[$schedule->user_id][$schedule->slot] = array(
$schedule->date->format('d/m/Y') => array(
'id' => $schedule->id,
'type' => $schedule->activity,
'text' => $schedule->description,
'id_lie' => $id_lie,
// $schedule->id_lie,
'model_lie' => $model_lie,
),
);
} else {
// same slot
if ($prevDate != $schedule->date) {
// new date
$arSchedules[$schedule->user_id][$schedule->slot][$schedule->date->format('d/m/Y')] = array(
'id' => $schedule->id,
'type' => $schedule->activity,
'text' => $schedule->description,
'id_lie' => $id_lie,
// $schedule->id_lie,
'model_lie' => $model_lie,
);
} else {
// same date
// should never be here
}
}//end if
}//end if
$prevUserId = $schedule->user_id;
$prevDate = $schedule->date;
$prevSlot = $schedule->slot;
}//end foreach
$weekCells = array();
for ($i = 0; $i < $nbweeks; $i++) {
$weekCells[] = array(
"num" => $date->addDays($i * 7)->weekOfYear,
"month" => $date->addDays($i * 7)->shortLocaleMonth,
"year" => $date->addDays($i * 7)->format('Y')
);
}
return view('schedule.index', compact('users', 'date', 'weekCells', 'arSchedules'));
}
public function setCellContent(StoreScheduleRequest $request)
{
$date = CarbonImmutable::createFromFormat('d/m/Y', $request->date);
$fill = $request->all();
$fill['date'] = $date;
$schedule = Schedule::updateOrCreate(['id' => $request->id], $fill);
$schedule->saveOrFail();
$id_lie = array('label' => null, 'value' => null);
if (!is_null($schedule->model_lie)) {
if (isset($schedule->relatedModel->name)) {
$id_lie = array('label' => $schedule->relatedModel->name, 'value' => $schedule->id_lie);
} else {
$id_lie = array('label' => 'Ticket ' . $schedule->id_lie, 'value' => $schedule->id_lie);
}
$model_lie = $schedule->model_lie;
} else {
$model_lie = array('label' => null, 'value' => null);
}
$arSchd = [
'id' => $schedule->id,
'user_id' => $schedule->user_id,
'date' => $schedule->date->format('d/m/Y'),
'activity' => $schedule->activity,
'description' => $schedule->description,
'id_lie' => $id_lie,
'model_lie' => $model_lie,
'slot' => $schedule->slot,
];
return \response()->json(['status' => true, 'sched' => $arSchd]);
}
public function eraseCellContent(Request $request)
{
$schedule = Schedule::findOrFail($request->id);
$schedule->delete();
return \response()->json(['status' => true]);
}
}

View file

@ -1,120 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Enums\ProjectStatus;
use App\Http\Requests\MacroSchedule\PostActivityRequest;
use App\Http\Requests\MacroSchedule\ShowMacroScheduleRequest;
use App\Models\MacroSchedule\Activity;
use App\Models\Project;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class ScheduleMacroController extends Controller
{
/**
* View Macro planning
*
* @param \App\Http\Requests\MacroSchedule\ShowMacroScheduleRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function show(ShowMacroScheduleRequest $request)
{
$numberOfWeeksToShow = \config('macroschedule.numberOfWeeksToShow');
$date = Carbon::now();
if ($request->date) {
$date = Carbon::createFromFormat('d/m/Y', $request->date);
}
/** @var \Illuminate\Support\Carbon $date The date from which to take activities */
$date->startOfWeek();
/** @var \Illuminate\Support\Collection $projects */
$projects = Project::where('status', '>', ProjectStatus::new())
->where('status', '<', ProjectStatus::finished())
->with(['activities' => function ($q) use ($date, $numberOfWeeksToShow) {
$q->whereDate('start', '>=', $date->toDateString())
->OrWhereDate('end', '<=', $date->clone()->addWeeks($numberOfWeeksToShow)->toDateString());
}])->with('markers')->orderBy('status')->orderBy('name')->get()->keyBy('id');
// * Key by date activities relation
$projects->map(function (Project $project) {
$project->setRelation('activities', $project->activities->keyBy('id'));
});
// * Map activities by datetime
$activities = collect();
$projects->pluck('activities')->map(function (Collection $projectActivities) use (&$activities) {
$projectActivities->map(function (Activity $activity) use (&$activities) {
$activities->push($activity);
});
});
// * Disponibility calculation
$loadCollection = collect();
/** @var array<\Illuminate\Support\Carbon> */
$period = $date->toPeriod($date->clone()->addWeeks($numberOfWeeksToShow), 12, 'hour')->toArray();
foreach ($period as $day) {
/** @var \Illuminate\Support\Collection */
$dayActivities = $activities->filter(function (Activity $activity) use ($day) {
return $day->betweenIncluded($activity->start, $activity->end);
});
/** @var integer total activités / hommes / demi journées */
$totalLoad = $dayActivities->sum('load');
$loadCollection->put($day->format('Y-m-d H:i:s'), $totalLoad / config('macroschedule.totalAvailableDevs'));
}
return view('macroplanning.view', compact(
'date',
'projects',
'date',
'numberOfWeeksToShow',
'loadCollection'
));
}
/**
* Save activity.
*
* @param PostActivityRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function postActivity(PostActivityRequest $request)
{
return DB::transaction(function () use ($request) {
$hasOverLap = false;
/** @var \App\Models\Project */
$project = Project::whereId($request->project_id)
->with('activities')->firstOrFail();
/** @var \App\Models\MacroSchedule\Activity */
$activity = Activity::whereId($request->id)->firstOrNew();
$activity->fill($request->validated());
$activity->project()->associate($project);
if (!$activity->saveOrFail()) {
response()->json('Une erreur est survenue lors de \'enregistrement');
}
// * Overload activities if necessary
$project->activities->map(function (Activity $periodActivity) use ($activity, &$hasOverLap) {
if (
$activity->id !== $periodActivity->id and
$activity->doesPeriodCoverActivity($periodActivity->start, $periodActivity->end)
) {
$hasOverLap = true;
$periodActivity->overlapUsingActivity($activity);
}
});
return response()->json([
'id' => $activity->id,
'hasOverlap' => $hasOverLap
]);
});
}
}

View file

@ -1,51 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Site;
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
use Kwaadpepper\CrudPolicies\Traits\CrudController;
class SiteController extends Controller
{
use CrudController {
__construct as __CrudConstructor;
index as crudIndex;
}
/**
* SiteController
*/
public function __construct()
{
parent::__construct();
$this->__CrudConstructor();
$this->authorizeResource(Site::class, 'site');
}
/** @var Site */
public static $modelClass = Site::class;
/**
* Crud Layout
*
* @var string
*/
public static $layout = 'layout.app';
/**
* Site.index crud
*
* @param CrudIndexRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(CrudIndexRequest $request)
{
/** @var \Illuminate\View\View */
$view = $this->crudIndex($request);
if ($request->ajax()) {
return $view;
}
return view('sites.index', $view->getData());
}
}

View file

@ -1,595 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Enums\TicketStatus;
use App\Enums\TicketType;
use App\Events\NotifySubscriptions;
use App\Events\TicketStatusChanged;
use App\Http\Requests\AssignTicketToUserRequest;
use App\Http\Requests\ChangeTicketStatus;
use App\Http\Requests\CreateMessage;
use App\Http\Requests\SortTickets;
use App\Http\Requests\StoreTicket;
use App\Http\Requests\UpdateMessage;
use App\Http\Requests\UpdateTicket;
use App\Lib\ToolboxHelper;
use App\Mail\NewTicket;
use App\Models\Message;
use App\Models\Site;
use App\Models\Ticket;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
class TicketController extends Controller
{
/**
* TicketController
*/
public function __construct()
{
parent::__construct();
$this->authorizeResource(Ticket::class, 'ticket');
}
/**
* Tickets List
*
* @param SortTickets $request
* @return \Illuminate\Http\JsonResponse|\Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index(SortTickets $request)
{
// * Handle Ajax
if ($request->ajax()) {
$tickets = Ticket::with(['user', 'assignedUser']);
if ($request->s) {
$tickets = $tickets->where('text', 'LIKE', "%$request->s%")
->orWhere('id', $request->s)
->orWhereHas('user', function ($q) use ($request) {
$q->where('name', 'LIKE', "%$request->s%");
});
}
/** @var \Illuminate/Pagination/LengthAwarePaginator $tickets */
$tickets = $tickets->paginate();
return \response()->json($tickets->getCollection()->map(function (Ticket $ticket) {
return [
'label' => sprintf(
'Ticket %d (%s): %s',
$ticket->id,
$ticket->user ? $ticket->user->name : trans('Utilisateur supprimé'),
Str::limit(\preg_replace('/[[:cntrl:]]+/', '', $ticket->text), 35)
),
'value' => $ticket->id
];
}));
}//end if
/** @var \App\Models\User */
$user = auth()->user();
$tickets = Ticket::with(['site', 'labels']);
if (!$user->isAdmin()) {
$tickets->whereHas('site', function ($q) use ($user) {
$q->whereHas('users', function ($q) use ($user) {
$q->whereId($user->id);
});
});
$tickets->where('is_internal', false);
} else {
$tickets->has('site');
}
$tickets->where(
'status',
($request->st == TicketStatus::archived()) ? '=' : '<>',
TicketStatus::archived()
);
$tickets = $this->searchTicket($tickets, $request);
$tickets = $this->filterTickets($tickets, $request);
$tickets = $tickets->paginate();
$sites = Site::select('id', 'name')->orderBy('name')->get();
$status = TicketStatus::toArray();
return view('ticket.index', compact('tickets', 'sites', 'status'));
}
/**
* Show Ticket
*
* @param Request $request
* @param Ticket $ticket
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function show(Request $request, Ticket $ticket)
{
if ($request->ajax()) {
return \response()->json([
'label' => sprintf(
'Ticket %d (%s): %s',
$ticket->id,
$ticket->user ? $ticket->user->email : __('Utilisateur supprimé'),
Str::limit(\preg_replace('/[[:cntrl:]]+/', '', $ticket->text), 35)
),
'value' => $ticket->id
]);
}
/** @var \App\Models\User */
$user = auth()->user();
if (!$user->can('update', $ticket)) {
abort(403);
}
if ($ticket->is_internal && !$user->can('changeInternalStatus', $ticket)) {
abort(403);
}
$messages = $ticket->messages()->orderBy('created_at', 'DESC')->get();
$isSubscribed = (bool)$ticket->subscriptions()->where('user_id', $user->id)->count();
return view('ticket.show', compact('ticket', 'messages', 'isSubscribed'));
}
/**
* Show create Form
*
* @return \Illuminate\Http\RedirectResponse
*/
public function create()
{
/** @var \App\Models\User */
$user = auth()->user();
if ($user->isAdmin()) {
$sites = Site::orderBy('name')->get();
} else {
$sites = $user->sites;
}
if (!count($sites)) {
return redirect()->route('sites.create')
->with('warning', trans('Vous devez tout d\'abord créer un site pour y ajouter un ticket'));
}
return view('ticket.create', compact('sites'));
}
/**
* Create ticket
*
* @param StoreTicket $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreTicket $request)
{
try {
return DB::transaction(function () use ($request) {
/** @var \App\Models\Site */
$site = Site::findOrFail($request->site_id);
/** @var \App\Models\User */
$user = auth()->user();
$ticket = new Ticket($request->validated());
/** @var \Illuminate\Http\UploadedFile|null */
$fileTicket = $request->file_ticket;
/** @var \Illuminate\Http\UploadedFile|null */
$fileTicket2 = $request->file_ticket2;
if ($fileTicket) {
$ticket->file = ToolboxHelper::storeImage($ticket->getTable(), $fileTicket);
}
if ($fileTicket2) {
$ticket->file2 = ToolboxHelper::storeImage($ticket->getTable(), $fileTicket2);
}
if ($request->labels) {
$ticket->labels()->sync($request->labels);
}
$ticket->user()->associate(auth()->user());
$ticket->site()->associate($site);
$ticket->saveOrFail();
$user->subscriptions()->toggle($ticket->id);
if (config('mail.MAIL_ADMIN')) {
Mail::to(config('mail.MAIL_ADMIN'))->send(new NewTicket($ticket));
} else {
throw new \ErrorException('Missing MAIL_ADMIN in .env');
}
return redirect()->route('ticket.show', $ticket)
->with('success', trans('Ticket enregistré !'));
});
} catch (\ErrorException $e) {
report($e);
Session::flash('error', trans('Une erreur est survenue'));
} //end try
return \back();
}
/**
* Show update form
*
* @param Ticket $ticket
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function edit(Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
if ($user->isAdmin()) {
$sites = Site::orderBy('name')->get();
} else {
$sites = $user->sites;
}
return view('ticket.edit', compact('ticket', 'sites'));
}
/**
* Update Model
*
* @param UpdateTicket $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateTicket $request, Ticket $ticket)
{
$ticket->fill($request->validated());
try {
return DB::transaction(function () use ($request, $ticket) {
/** @var \App\Models\Site */
$site = Site::findOrFail($request->site_id);
/** @var \Illuminate\Http\UploadedFile|null */
$fileTicket = $request->file_ticket;
/** @var \Illuminate\Http\UploadedFile|null */
$fileTicket2 = $request->file_ticket2;
if ($fileTicket) {
$ticket->file = ToolboxHelper::storeImage($ticket->getTable(), $fileTicket);
}
if ($fileTicket2) {
$ticket->file2 = ToolboxHelper::storeImage($ticket->getTable(), $fileTicket2);
}
if ($request->labels) {
$ticket->labels()->sync($request->labels);
}
$ticket->site()->associate($site);
$ticket->saveOrFail();
return redirect()->route('ticket.edit', $ticket->id)
->with('success', 'Modifications enregistrées !');
});
} catch (\ErrorException $e) {
report($e);
Session::flash('error', trans('Une erreur est survenue'));
} //end try
return \back();
}
/**
* Change ticket Status
*
* @param ChangeTicketStatus $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function changeStatus(ChangeTicketStatus $request, Ticket $ticket)
{
$ticket->fill($request->validated());
$ticket->saveOrFail();
return back()
->with('warning', trans('Le status à été modifié'));
}
/**
* Add a new Message to the Ticket
*
* @param CreateMessage $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function createMessage(CreateMessage $request, Ticket $ticket)
{
try {
return DB::transaction(function () use ($request, $ticket) {
/** @var \Illuminate\Http\UploadedFile|null */
$fileMessage = $request->file_message;
$message = new Message($request->validated());
$message->user()->associate(auth()->user());
$message->ticket()->associate($ticket);
/** @var \App\Models\User */
$user = auth()->user();
if ($request->subscribe) {
if (!$user->subscriptions()->find($ticket->id)) {
$user->subscriptions()->attach($ticket->id);
}
} elseif ($user->subscriptions()->find($ticket->id)) {
$user->subscriptions()->detach($ticket->id);
}
$message->saveOrFail();
if ($fileMessage) {
$message->file = ToolboxHelper::storeImage($message->getTable(), $fileMessage);
$message->saveOrFail();
}
return back()
->with('success', trans('Votre message à été ajouté'));
});
} catch (\ErrorException $e) {
report($e);
Session::flash('error', trans('Une erreur est survenue'));
} //end try
return back();
}
/**
* Update Message
*
* @param UpdateMessage $request
* @param Ticket $ticket
* @param Message $message
* @return \Illuminate\Http\RedirectResponse
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
*/
public function updateMessage(UpdateMessage $request, Ticket $ticket, Message $message)
{
$message->message = $request->message;
$message->saveOrFail();
return back()
->with('success', trans('Votre message à bien été modifié'));
}
/**
* Change ticket status to archived
*
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function setToArchive(Ticket $ticket)
{
$ticket->status = TicketStatus::archived();
$ticket->saveOrFail();
return redirect()->route('ticket.index')
->with('warning', trans('Le ticket est archivé'));
}
/**
* Subscribe to ticket
*
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function subscribe(Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
$user->subscriptions()->toggle($ticket->id);
if ($user->subscriptions()->where('ticket_id', $ticket->id)->exists()) {
return back()
->with('success', trans('Vous avez été inscrit'));
}
return back()->with('warning', trans('Vous avez été désinscrit'));
}
/**
* Reopen ticket
*
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function reopen(Ticket $ticket)
{
$message = trans(':ticketName à réouvert le ticket n°:ticketNumber', [
'ticketName' => $ticket->user->name,
'ticketNumber' => $ticket->id,
]);
$oldStatus = $ticket->status;
$ticket->status = TicketStatus::inprogress();
$ticket->saveQuietly();
event(new TicketStatusChanged($ticket, $oldStatus, null, $message));
event(new NotifySubscriptions($ticket, $message, collect([$ticket->user])));
/** @var \App\Models\User */
$user = auth()->user();
$user->subscriptions()->toggle($ticket->id);
return back()->with('warning', trans('Votre ticket à été réouvert.'));
}
/**
* Assign ticket to user ticket
*
* @param AssignTicketToUserRequest $request
* @param Ticket $ticket
* @return \Illuminate\Http\RedirectResponse
*/
public function assignTo(AssignTicketToUserRequest $request, Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
/** @var \App\Models\User|null */
if ($assignedUser = User::whereId($request->assign)->first()) {
$message = trans(':admin à assigné le ticket n°:ticketNumber à :assignedAdmin', [
'admin' => $user->name,
'ticketNumber' => $ticket->id,
'assignedAdmin' => $assignedUser->name,
]);
$ticket->assignedUser()->associate($assignedUser);
} else {
$message = trans(
':admin modifié l\'assignation du ticket n°:ticketNumber, il n\'est plus assigné à quelqu\'un.',
[
'admin' => $user->name,
'ticketNumber' => $ticket->id,
]
);
$ticket->assignedUser()->dissociate();
}
$ticket->saveQuietly();
/** @var \App\Enums\TicketStatus */
$oldStatus = $ticket->status;
event(new TicketStatusChanged($ticket, $oldStatus, null, $message));
event(new NotifySubscriptions($ticket, $message, collect([$ticket->user])));
/** @var \App\Models\User */
$user = auth()->user();
$user->subscriptions()->toggle($ticket->id);
if ($assignedUser) {
return back()->with('info', trans('Le ticket à été assigné à :assignedUser', [
'assignedUser' => $assignedUser->name
]));
}
return back()->with('info', trans('Le ticket n\'est plus assigné à personne'));
}
// * PRIVATES
/**
* Filter Tickets request constructor
*
* @param Builder $tickets
* @param Request $request
* @return Builder
*/
private function filterTickets(Builder $tickets, Request $request): Builder
{
if ($request->rst) {
Session::remove('tickets.ass');
Session::remove('tickets.st');
Session::remove('tickets.pr');
Session::remove('tickets.sort_col');
Session::remove('tickets.sort_way');
}
if ($request->assr) {
Session::remove('tickets.ass');
}
if ($request->prs) {
Session::remove('tickets.pr');
}
if ($request->sts) {
Session::remove('tickets.st');
}
if ($request->sort_col) {
Session::put('tickets.sort_col', $request->sort_col);
}
if ($request->sort_way) {
Session::put('tickets.sort_way', $request->sort_way);
}
if ($request->pr) {
Session::put('tickets.pr', $request->pr);
}
if ($request->st) {
Session::put('tickets.st', $request->st);
}
if ($request->ass) {
Session::put('tickets.ass', $request->ass);
}
Session::save();
if (Session::has('tickets.pr')) {
$tickets->where('site_id', Session::get('tickets.pr'));
}
if (Session::has('tickets.ass')) {
$tickets->whereHas('assignedUser', function ($q) {
$q->whereId(Session::get('tickets.ass'));
});
}
if (Session::has('tickets.st')) {
$tickets->where('status', Session::get('tickets.st'));
}
if (
Session::has('tickets.sort_col') and
Session::has('tickets.sort_way') and
in_array(Session::get('tickets.sort_col'), [
'id', 'site_id', 'created_at', 'created_by',
'type', 'status', 'assigned_to'
])
) {
$tickets->orderBy(
Session::get('tickets.sort_col'),
Session::get('tickets.sort_way')
);
} else {
$tickets->orderBy('id', 'DESC');
}
return $tickets;
}
/**
* Search ticket sql request constructor
*
* @param Builder $tickets
* @param Request $request
* @return Builder
*/
private function searchTicket(Builder $tickets, Request $request): Builder
{
if ($request->exists('search')) {
if (empty($request->search)) {
Session::remove('tickets.search');
} else {
Session::put('tickets.search', $request->search);
}
}
if (!Session::has('tickets.search')) {
return $tickets;
}
return $this->searchQuery($tickets, Session::get('tickets.search'), function ($q) {
$words = explode(' ', Session::get('tickets.search'));
if (\is_array($words)) {
foreach ($words as $word) {
if (!strlen($word)) {
continue;
}
$s = collect(TicketStatus::toArray())->filter(function (TicketStatus $t) use ($word) {
return Str::slug($t->label) === Str::slug($word);
})->map(function (TicketStatus $ticket) {
return $ticket->value;
});
$t = collect(TicketType::toArray())->filter(function (TicketType $s) use ($word) {
return Str::slug($s->label) === Str::slug($word);
})->map(function (TicketType $ticket) {
return $ticket->value;
});
$q->orWhere('id', $word)
->orWhereIn('status', $s)
->orWhereIn('type', $t)
->orWhereHas('user', function ($q) use ($word) {
$q->where('name', 'LIKE', "%$word%");
});
} //end foreach
} //end if
}, 'text', 'file', 'file2');
}
}

Some files were not shown because too many files have changed in this diff Show more