Issues (3877)

QuoteApproval/QuoteApprovalRequestValidator.php (5 issues)

1
<?php
2
3
/**
4
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace Spryker\Zed\QuoteApproval\Business\QuoteApproval;
9
10
use Generated\Shared\Transfer\CustomerTransfer;
11
use Generated\Shared\Transfer\MessageTransfer;
12
use Generated\Shared\Transfer\QuoteApprovalRequestTransfer;
13
use Generated\Shared\Transfer\QuoteApprovalResponseTransfer;
14
use Generated\Shared\Transfer\QuoteTransfer;
15
use Spryker\Shared\QuoteApproval\QuoteApprovalConfig;
16
use Spryker\Zed\Kernel\PermissionAwareTrait;
17
use Spryker\Zed\QuoteApproval\Business\Permission\ContextProvider\PermissionContextProviderInterface;
18
use Spryker\Zed\QuoteApproval\Business\Quote\QuoteStatusCalculatorInterface;
19
use Spryker\Zed\QuoteApproval\Communication\Plugin\Permission\ApproveQuotePermissionPlugin;
20
use Spryker\Zed\QuoteApproval\Dependency\Facade\QuoteApprovalToCompanyUserFacadeInterface;
21
use Spryker\Zed\QuoteApproval\Dependency\Facade\QuoteApprovalToQuoteFacadeInterface;
22
use Spryker\Zed\QuoteApproval\Persistence\QuoteApprovalRepositoryInterface;
23
24
class QuoteApprovalRequestValidator implements QuoteApprovalRequestValidatorInterface
25
{
26
    use PermissionAwareTrait;
27
28
    /**
29
     * @var string
30
     */
31
    protected const GLOSSARY_KEY_PERMISSION_FAILED = 'global.permission.failed';
32
33
    /**
34
     * @var string
35
     */
36
    protected const GLOSSARY_KEY_APPROVER_CANT_APPROVE_QUOTE = 'quote_approval.create.approver_cant_approve_quote';
37
38
    /**
39
     * @var string
40
     */
41
    protected const GLOSSARY_KEY_YOU_CANT_APPROVE_QUOTE = 'quote_approval.create.you_cant_approve_quote';
42
43
    /**
44
     * @var string
45
     */
46
    protected const GLOSSARY_KEY_QUOTE_ALREADY_APPROVED = 'quote_approval.create.quote_already_approved';
47
48
    /**
49
     * @var string
50
     */
51
    protected const GLOSSARY_KEY_QUOTE_ALREADY_DECLINED = 'quote_approval.create.quote_already_declined';
52
53
    /**
54
     * @var string
55
     */
56
    protected const GLOSSARY_KEY_QUOTE_ALREADY_CANCELLED = 'quote_approval.create.quote_already_cancelled';
57
58
    /**
59
     * @var string
60
     */
61
    protected const GLOSSARY_KEY_QUOTE_ALREADY_WAITING_FOR_APPROVAL = 'quote_approval.create.quote_already_waiting_for_approval';
62
63
    /**
64
     * @var string
65
     */
66
    protected const GLOSSARY_KEY_ONLY_QUOTE_OWNER_CAN_SEND_APPROVAL_REQUEST = 'quote_approval.create.only_quote_owner_can_send_request';
67
68
    /**
69
     * @var string
70
     */
71
    protected const GLOSSARY_KEY_DO_NOT_HAVE_PERMISSION_TO_CANCEL_APPROVAL_REQUEST = 'quote_approval.cancel.do_not_have_permission';
72
73
    /**
74
     * @var string
75
     */
76
    protected const GLOSSARY_KEY_CANT_SEND_FOR_APPROVE_EMPTY_QUOTE = 'quote_approval.create.cant_send_for_approve_empty_quote';
77
78
    /**
79
     * @var \Spryker\Zed\QuoteApproval\Business\Quote\QuoteStatusCalculatorInterface
80
     */
81
    protected $quoteStatusCalculator;
82
83
    /**
84
     * @var \Spryker\Zed\QuoteApproval\Dependency\Facade\QuoteApprovalToQuoteFacadeInterface
85
     */
86
    protected $quoteFacade;
87
88
    /**
89
     * @var \Spryker\Zed\QuoteApproval\Persistence\QuoteApprovalRepositoryInterface
90
     */
91
    protected $quoteApprovalRepository;
92
93
    /**
94
     * @var \Spryker\Zed\QuoteApproval\Dependency\Facade\QuoteApprovalToCompanyUserFacadeInterface
95
     */
96
    protected $companyUserFacade;
97
98
    /**
99
     * @var \Spryker\Zed\QuoteApproval\Business\Permission\ContextProvider\PermissionContextProviderInterface
100
     */
101
    protected $permissionContextProvider;
102
103
    /**
104
     * @param \Spryker\Zed\QuoteApproval\Dependency\Facade\QuoteApprovalToQuoteFacadeInterface $quoteFacade
105
     * @param \Spryker\Zed\QuoteApproval\Business\Quote\QuoteStatusCalculatorInterface $quoteStatusCalculator
106
     * @param \Spryker\Zed\QuoteApproval\Persistence\QuoteApprovalRepositoryInterface $quoteApprovalRepository
107
     * @param \Spryker\Zed\QuoteApproval\Dependency\Facade\QuoteApprovalToCompanyUserFacadeInterface $companyUserFacade
108
     * @param \Spryker\Zed\QuoteApproval\Business\Permission\ContextProvider\PermissionContextProviderInterface $permissionContextProvider
109
     */
110
    public function __construct(
111
        QuoteApprovalToQuoteFacadeInterface $quoteFacade,
112
        QuoteStatusCalculatorInterface $quoteStatusCalculator,
113
        QuoteApprovalRepositoryInterface $quoteApprovalRepository,
114
        QuoteApprovalToCompanyUserFacadeInterface $companyUserFacade,
115
        PermissionContextProviderInterface $permissionContextProvider
116
    ) {
117
        $this->quoteFacade = $quoteFacade;
118
        $this->quoteStatusCalculator = $quoteStatusCalculator;
119
        $this->quoteApprovalRepository = $quoteApprovalRepository;
120
        $this->companyUserFacade = $companyUserFacade;
121
        $this->permissionContextProvider = $permissionContextProvider;
122
    }
123
124
    /**
125
     * @param \Generated\Shared\Transfer\QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer
126
     *
127
     * @return \Generated\Shared\Transfer\QuoteApprovalResponseTransfer
128
     */
129
    public function validateQuoteApprovalCreateRequest(QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer): QuoteApprovalResponseTransfer
130
    {
131
        $this->assertQuoteApprovalCreateRequestValid($quoteApprovalRequestTransfer);
132
133
        $quoteTransfer = $this->resolveQuote($quoteApprovalRequestTransfer);
134
135
        if (!$quoteTransfer->getItems()->count()) {
136
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_CANT_SEND_FOR_APPROVE_EMPTY_QUOTE);
137
        }
138
139
        if (!$this->isQuoteOwner($quoteTransfer, $quoteApprovalRequestTransfer->getRequesterCompanyUserId())) {
140
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_ONLY_QUOTE_OWNER_CAN_SEND_APPROVAL_REQUEST);
141
        }
142
143
        if (!$this->isApproverCanApproveQuote($quoteTransfer, $quoteApprovalRequestTransfer->getApproverCompanyUserId())) {
144
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_APPROVER_CANT_APPROVE_QUOTE);
145
        }
146
147
        if ($this->isQuoteWaitingForApproval($quoteTransfer)) {
148
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_QUOTE_ALREADY_WAITING_FOR_APPROVAL);
149
        }
150
151
        if ($this->isQuoteApproved($quoteTransfer)) {
152
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_QUOTE_ALREADY_APPROVED);
153
        }
154
155
        return $this->createSuccessfullValidationResponseTransfer()
156
            ->setQuote($quoteTransfer);
157
    }
158
159
    /**
160
     * @param \Generated\Shared\Transfer\QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer
161
     *
162
     * @return \Generated\Shared\Transfer\QuoteApprovalResponseTransfer
163
     */
164
    public function validateQuoteApprovalRemoveRequest(QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer): QuoteApprovalResponseTransfer
165
    {
166
        $quoteTransfer = $this->findQuoteByIdQuoteApproval($quoteApprovalRequestTransfer->getIdQuoteApproval());
167
168
        if (
169
            !$this->isQuoteOwner($quoteTransfer, $quoteApprovalRequestTransfer->getRequesterCompanyUserId())
0 ignored issues
show
It seems like $quoteTransfer can also be of type null; however, parameter $quoteTransfer of Spryker\Zed\QuoteApprova...lidator::isQuoteOwner() does only seem to accept Generated\Shared\Transfer\QuoteTransfer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
            !$this->isQuoteOwner(/** @scrutinizer ignore-type */ $quoteTransfer, $quoteApprovalRequestTransfer->getRequesterCompanyUserId())
Loading history...
170
            && !$this->isRemoveRequestSentByApprover($quoteApprovalRequestTransfer)
171
        ) {
172
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_DO_NOT_HAVE_PERMISSION_TO_CANCEL_APPROVAL_REQUEST);
173
        }
174
175
        return $this->createSuccessfullValidationResponseTransfer()
176
            ->setQuote($quoteTransfer);
177
    }
178
179
    /**
180
     * @param \Generated\Shared\Transfer\QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer
181
     *
182
     * @return \Generated\Shared\Transfer\QuoteApprovalResponseTransfer
183
     */
184
    public function validateQuoteApprovalRequest(QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer): QuoteApprovalResponseTransfer
185
    {
186
        $this->assertQuoteApprovalRequestValid($quoteApprovalRequestTransfer);
187
        $quoteApprovalTransfer = $this->quoteApprovalRepository
188
            ->findQuoteApprovalById($quoteApprovalRequestTransfer->getIdQuoteApproval());
189
        $quoteTransfer = $this->findQuoteByIdQuoteApproval($quoteApprovalTransfer->getIdQuoteApproval());
190
191
        if ($this->isQuoteApprovalRequestCanceled($quoteTransfer)) {
0 ignored issues
show
It seems like $quoteTransfer can also be of type null; however, parameter $quoteTransfer of Spryker\Zed\QuoteApprova...provalRequestCanceled() does only seem to accept Generated\Shared\Transfer\QuoteTransfer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

191
        if ($this->isQuoteApprovalRequestCanceled(/** @scrutinizer ignore-type */ $quoteTransfer)) {
Loading history...
192
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_QUOTE_ALREADY_CANCELLED);
193
        }
194
195
        if ($this->isQuoteApproved($quoteTransfer)) {
0 ignored issues
show
It seems like $quoteTransfer can also be of type null; however, parameter $quoteTransfer of Spryker\Zed\QuoteApprova...ator::isQuoteApproved() does only seem to accept Generated\Shared\Transfer\QuoteTransfer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

195
        if ($this->isQuoteApproved(/** @scrutinizer ignore-type */ $quoteTransfer)) {
Loading history...
196
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_QUOTE_ALREADY_APPROVED);
197
        }
198
199
        if ($this->isQuoteDeclined($quoteTransfer)) {
0 ignored issues
show
It seems like $quoteTransfer can also be of type null; however, parameter $quoteTransfer of Spryker\Zed\QuoteApprova...ator::isQuoteDeclined() does only seem to accept Generated\Shared\Transfer\QuoteTransfer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

199
        if ($this->isQuoteDeclined(/** @scrutinizer ignore-type */ $quoteTransfer)) {
Loading history...
200
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_QUOTE_ALREADY_DECLINED);
201
        }
202
203
        if (!$this->isApproverCanApproveQuote($quoteTransfer, $quoteApprovalRequestTransfer->getApproverCompanyUserId())) {
0 ignored issues
show
It seems like $quoteTransfer can also be of type null; however, parameter $quoteTransfer of Spryker\Zed\QuoteApprova...proverCanApproveQuote() does only seem to accept Generated\Shared\Transfer\QuoteTransfer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

203
        if (!$this->isApproverCanApproveQuote(/** @scrutinizer ignore-type */ $quoteTransfer, $quoteApprovalRequestTransfer->getApproverCompanyUserId())) {
Loading history...
204
            return $this->createUnsuccessfulValidationResponseTransfer(static::GLOSSARY_KEY_YOU_CANT_APPROVE_QUOTE);
205
        }
206
207
        return $this->createSuccessfullValidationResponseTransfer()
208
            ->setQuote($quoteTransfer)
209
            ->setQuoteApproval($quoteApprovalTransfer);
210
    }
211
212
    /**
213
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
214
     * @param \Generated\Shared\Transfer\QuoteTransfer $persistentQuoteTransfer
215
     *
216
     * @return \Generated\Shared\Transfer\QuoteTransfer
217
     */
218
    protected function mergeQuotes(QuoteTransfer $quoteTransfer, QuoteTransfer $persistentQuoteTransfer): QuoteTransfer
219
    {
220
        $quoteTransfer->fromArray($persistentQuoteTransfer->modifiedToArray(), true);
221
222
        return $quoteTransfer;
223
    }
224
225
    /**
226
     * @param \Generated\Shared\Transfer\QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer
227
     *
228
     * @return void
229
     */
230
    protected function assertQuoteApprovalRequestValid(QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer): void
231
    {
232
        $quoteApprovalRequestTransfer->requireApproverCompanyUserId()
233
            ->requireIdQuoteApproval();
234
    }
235
236
    /**
237
     * @param \Generated\Shared\Transfer\QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer
238
     *
239
     * @return void
240
     */
241
    protected function assertQuoteApprovalCreateRequestValid(QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer): void
242
    {
243
        $quoteApprovalRequestTransfer->requireApproverCompanyUserId()
244
            ->requireRequesterCompanyUserId();
245
246
        // For BC reasons only.
247
        if (!$quoteApprovalRequestTransfer->getQuote()) {
248
            $quoteApprovalRequestTransfer->requireIdQuote();
249
250
            return;
251
        }
252
253
        $quoteApprovalRequestTransfer->requireQuote();
254
    }
255
256
    /**
257
     * @param string $message
258
     *
259
     * @return \Generated\Shared\Transfer\QuoteApprovalResponseTransfer
260
     */
261
    protected function createUnsuccessfulValidationResponseTransfer(string $message): QuoteApprovalResponseTransfer
262
    {
263
        $quoteApprovalResponseTransfer = new QuoteApprovalResponseTransfer();
264
        $quoteApprovalResponseTransfer->setIsSuccessful(false);
265
        $quoteApprovalResponseTransfer->addMessage(
266
            (new MessageTransfer())->setValue($message),
267
        );
268
269
        return $quoteApprovalResponseTransfer;
270
    }
271
272
    /**
273
     * @return \Generated\Shared\Transfer\QuoteApprovalResponseTransfer
274
     */
275
    protected function createSuccessfullValidationResponseTransfer(): QuoteApprovalResponseTransfer
276
    {
277
        $quoteApprovalResponseTransfer = new QuoteApprovalResponseTransfer();
278
        $quoteApprovalResponseTransfer->setIsSuccessful(true);
279
280
        return $quoteApprovalResponseTransfer;
281
    }
282
283
    /**
284
     * @param int $idQuote
285
     *
286
     * @return \Generated\Shared\Transfer\QuoteTransfer
287
     */
288
    protected function getQuoteById(int $idQuote): QuoteTransfer
289
    {
290
        $quoteResponseTransfer = $this->quoteFacade->findQuoteById($idQuote);
291
        $quoteResponseTransfer->requireQuoteTransfer();
292
        $quoteTransfer = $quoteResponseTransfer->getQuoteTransfer();
293
        $quoteTransfer->setCustomer(
294
            (new CustomerTransfer())->setCustomerReference($quoteTransfer->getCustomerReference()),
295
        );
296
297
        return $quoteTransfer;
298
    }
299
300
    /**
301
     * @param \Generated\Shared\Transfer\QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer
302
     *
303
     * @return bool
304
     */
305
    protected function isRemoveRequestSentByApprover(QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer): bool
306
    {
307
        $quoteApprovalTransfer = $this->quoteApprovalRepository->findQuoteApprovalById(
308
            $quoteApprovalRequestTransfer->getIdQuoteApproval(),
309
        );
310
311
        return $quoteApprovalTransfer->getApproverCompanyUserId() === $quoteApprovalRequestTransfer->getRequesterCompanyUserId();
312
    }
313
314
    /**
315
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
316
     * @param int $idCompanyUser
317
     *
318
     * @return bool
319
     */
320
    protected function isQuoteOwner(QuoteTransfer $quoteTransfer, int $idCompanyUser): bool
321
    {
322
        $companyUserTransfer = $this->companyUserFacade->getCompanyUserById($idCompanyUser);
323
324
        return $quoteTransfer->getCustomerReference() === $companyUserTransfer->getCustomer()->getCustomerReference();
325
    }
326
327
    /**
328
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
329
     * @param int $idCompanyUser
330
     *
331
     * @return bool
332
     */
333
    protected function isApproverCanApproveQuote(QuoteTransfer $quoteTransfer, int $idCompanyUser): bool
334
    {
335
        return $this->can(
336
            ApproveQuotePermissionPlugin::KEY,
337
            $idCompanyUser,
338
            $this->permissionContextProvider->provideContext($quoteTransfer),
339
        );
340
    }
341
342
    /**
343
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
344
     *
345
     * @return bool
346
     */
347
    protected function isQuoteApproved(QuoteTransfer $quoteTransfer): bool
348
    {
349
        return $this->quoteStatusCalculator->calculateQuoteStatus($quoteTransfer) === QuoteApprovalConfig::STATUS_APPROVED;
350
    }
351
352
    /**
353
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
354
     *
355
     * @return bool
356
     */
357
    protected function isQuoteWaitingForApproval(QuoteTransfer $quoteTransfer): bool
358
    {
359
        return $this->quoteStatusCalculator->calculateQuoteStatus($quoteTransfer) === QuoteApprovalConfig::STATUS_WAITING;
360
    }
361
362
    /**
363
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
364
     *
365
     * @return bool
366
     */
367
    protected function isQuoteApprovalRequestCanceled(QuoteTransfer $quoteTransfer): bool
368
    {
369
        return $this->quoteStatusCalculator->calculateQuoteStatus($quoteTransfer) === null;
370
    }
371
372
    /**
373
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
374
     *
375
     * @return bool
376
     */
377
    protected function isQuoteDeclined(QuoteTransfer $quoteTransfer): bool
378
    {
379
        return $this->quoteStatusCalculator->calculateQuoteStatus($quoteTransfer) === QuoteApprovalConfig::STATUS_DECLINED;
380
    }
381
382
    /**
383
     * @param int $idQuoteApproval
384
     *
385
     * @return \Generated\Shared\Transfer\QuoteTransfer|null
386
     */
387
    protected function findQuoteByIdQuoteApproval(int $idQuoteApproval): ?QuoteTransfer
388
    {
389
        $idQuote = $this->quoteApprovalRepository->findIdQuoteByIdQuoteApproval($idQuoteApproval);
390
391
        if ($idQuote === null) {
392
            return null;
393
        }
394
395
        return $this->getQuoteById($idQuote);
396
    }
397
398
    /**
399
     * @param \Generated\Shared\Transfer\QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer
400
     *
401
     * @return \Generated\Shared\Transfer\QuoteTransfer
402
     */
403
    protected function resolveQuote(QuoteApprovalRequestTransfer $quoteApprovalRequestTransfer): QuoteTransfer
404
    {
405
        $idQuote = $quoteApprovalRequestTransfer->getIdQuote() ?? $quoteApprovalRequestTransfer->getQuote()->getIdQuote();
406
407
        $quoteTransfer = $this->getQuoteById($idQuote);
408
409
        if (!$quoteApprovalRequestTransfer->getQuote()) {
410
            return $quoteTransfer;
411
        }
412
413
        return $this->mergeQuotes(
414
            $quoteApprovalRequestTransfer->getQuote(),
415
            $quoteTransfer,
416
        );
417
    }
418
}
419