AddConsole   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 143
dl 0
loc 224
rs 10
c 0
b 0
f 0
wmc 6

2 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 25 2
B execute() 0 171 4
1
<?php
2
3
/**
4
 * This file is part of byrokrat\giroapp.
5
 *
6
 * byrokrat\giroapp is free software: you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * byrokrat\giroapp is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with byrokrat\giroapp. If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * Copyright 2016-21 Hannes Forsgård
20
 */
21
22
declare(strict_types=1);
23
24
namespace byrokrat\giroapp\Console;
25
26
use byrokrat\giroapp\CommandBus\AddDonor;
27
use byrokrat\giroapp\CommandBus\UpdateAttribute;
28
use byrokrat\giroapp\CommandBus\UpdateComment;
29
use byrokrat\giroapp\CommandBus\UpdateEmail;
30
use byrokrat\giroapp\CommandBus\UpdateName;
31
use byrokrat\giroapp\CommandBus\UpdatePhone;
32
use byrokrat\giroapp\CommandBus\UpdatePostalAddress;
33
use byrokrat\giroapp\CommandBus\UpdateState;
34
use byrokrat\giroapp\DependencyInjection;
35
use byrokrat\giroapp\Domain\MandateSources;
36
use byrokrat\giroapp\Domain\NewDonor;
37
use byrokrat\giroapp\Domain\PostalAddress;
38
use byrokrat\giroapp\Domain\State\NewMandate;
39
use byrokrat\giroapp\Validator;
40
use Money\Currency;
41
use Money\Money;
42
use Symfony\Component\Console\Command\Command;
43
use Symfony\Component\Console\Input\InputOption;
44
use Symfony\Component\Console\Input\InputInterface;
45
use Symfony\Component\Console\Output\OutputInterface;
46
use Symfony\Component\Console\Helper\QuestionHelper;
47
48
final class AddConsole implements ConsoleInterface
49
{
50
    use DependencyInjection\AccountFactoryProperty;
51
    use DependencyInjection\CommandBusProperty;
52
    use DependencyInjection\DonorRepositoryProperty;
53
    use DependencyInjection\MoneyParserProperty;
54
    use DependencyInjection\IdFactoryProperty;
55
    use Helper\DryRun;
56
57
    private const OPTIONS = [
58
        self::OPTION_SOURCE,
59
        self::OPTION_ID,
60
        self::OPTION_PAYER_NUMBER,
61
        self::OPTION_ACCOUNT,
62
        self::OPTION_NAME,
63
        self::OPTION_AMOUNT,
64
        self::OPTION_ADDRESS1,
65
        self::OPTION_ADDRESS2,
66
        self::OPTION_ADDRESS3,
67
        self::OPTION_POSTAL_CODE,
68
        self::OPTION_POSTAL_CITY,
69
        self::OPTION_EMAIL,
70
        self::OPTION_PHONE,
71
        self::OPTION_COMMENT,
72
    ];
73
74
    public function configure(Command $command): void
75
    {
76
        $command->setName('add');
77
        $command->setDescription('Add a new donor');
78
        $command->setHelp('Register a new mandate in database');
79
80
        foreach (self::OPTIONS as $option) {
81
            $command->addOption($option, null, InputOption::VALUE_REQUIRED, self::OPTION_DESCS[$option]);
82
        }
83
84
        $command->addOption(
85
            self::OPTION_ATTR_KEY,
86
            null,
87
            InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
88
            self::OPTION_DESCS[self::OPTION_ATTR_KEY]
89
        );
90
91
        $command->addOption(
92
            self::OPTION_ATTR_VALUE,
93
            null,
94
            InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
95
            self::OPTION_DESCS[self::OPTION_ATTR_VALUE]
96
        );
97
98
        $this->configureDryRun($command);
99
    }
100
101
    public function execute(InputInterface $input, OutputInterface $output): void
102
    {
103
        $inputReader = new Helper\InputReader($input, $output, new QuestionHelper());
104
105
        $sources = ['p' => MandateSources::MANDATE_SOURCE_PAPER, 'o' => MandateSources::MANDATE_SOURCE_ONLINE_FORM];
106
107
        $mandateSource = $inputReader->readInput(
108
            self::OPTION_SOURCE,
109
            Helper\QuestionFactory::createChoiceQuestion(
110
                self::OPTION_DESCS[self::OPTION_SOURCE],
111
                $sources,
112
                MandateSources::MANDATE_SOURCE_ONLINE_FORM
113
            ),
114
            new Validator\ChoiceValidator($sources)
115
        );
116
117
        /** @var \byrokrat\id\IdInterface */
118
        $donorId = null;
119
120
        $inputReader->readInput(
121
            self::OPTION_ID,
122
            Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_ID]),
123
            new Validator\ValidatorCollection(
124
                new Validator\IdValidator(),
125
                new Validator\CallbackValidator(function (string $value) use (&$donorId) {
126
                    $donorId = $this->idFactory->createId($value);
127
                })
128
            )
129
        );
130
131
        $payerNumber = $inputReader->readInput(
132
            self::OPTION_PAYER_NUMBER,
133
            Helper\QuestionFactory::createQuestion(
134
                self::OPTION_DESCS[self::OPTION_PAYER_NUMBER],
135
                $donorId->format('Ssk')
136
            ),
137
            new Validator\PayerNumberValidator()
138
        );
139
140
        /** @var \byrokrat\banking\AccountNumber */
141
        $account = null;
142
143
        $inputReader->readInput(
144
            self::OPTION_ACCOUNT,
145
            Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_ACCOUNT])->setAutocompleterValues(
146
                ["3300,{$donorId->format('Ssk')}"]
147
            ),
148
            new Validator\ValidatorCollection(
149
                new Validator\AccountValidator(),
150
                new Validator\CallbackValidator(function (string $value) use (&$account) {
151
                    $account = $this->accountFactory->createAccount($value);
152
                })
153
            )
154
        );
155
156
        $donationAmount = $this->moneyParser->parse(
157
            $inputReader->readInput(
158
                self::OPTION_AMOUNT,
159
                Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_AMOUNT]),
160
                new Validator\ValidatorCollection(
161
                    new Validator\NotEmptyValidator(),
162
                    new Validator\NumericValidator()
163
                )
164
            ),
165
            new Currency('SEK')
166
        );
167
168
        $name = $inputReader->readInput(
169
            self::OPTION_NAME,
170
            Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_NAME]),
171
            new Validator\ValidatorCollection(
172
                new Validator\StringValidator(),
173
                new Validator\NotEmptyValidator()
174
            )
175
        );
176
177
        $postalAddress = new PostalAddress(
178
            $inputReader->readInput(
179
                self::OPTION_ADDRESS1,
180
                Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_ADDRESS1], ''),
181
                new Validator\StringValidator()
182
            ),
183
            $inputReader->readInput(
184
                self::OPTION_ADDRESS2,
185
                Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_ADDRESS2], ''),
186
                new Validator\StringValidator()
187
            ),
188
            $inputReader->readInput(
189
                self::OPTION_ADDRESS3,
190
                Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_ADDRESS3], ''),
191
                new Validator\StringValidator()
192
            ),
193
            $inputReader->readInput(
194
                self::OPTION_POSTAL_CODE,
195
                Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_POSTAL_CODE], ''),
196
                new Validator\PostalCodeValidator()
197
            ),
198
            $inputReader->readInput(
199
                self::OPTION_POSTAL_CITY,
200
                Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_POSTAL_CITY], ''),
201
                new Validator\StringValidator()
202
            )
203
        );
204
205
        $email = $inputReader->readInput(
206
            self::OPTION_EMAIL,
207
            Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_EMAIL], ''),
208
            new Validator\EmailValidator()
209
        );
210
211
        $phone = $inputReader->readInput(
212
            self::OPTION_PHONE,
213
            Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_PHONE], ''),
214
            new Validator\PhoneValidator()
215
        );
216
217
        $comment = $inputReader->readInput(
218
            self::OPTION_COMMENT,
219
            Helper\QuestionFactory::createQuestion(self::OPTION_DESCS[self::OPTION_COMMENT], ''),
220
            new Validator\StringValidator()
221
        );
222
223
        $attributes = [];
224
225
        /** @var array<string> */
226
        $attrKeys = $input->getOption(self::OPTION_ATTR_KEY);
227
228
        /** @var array<string> */
229
        $attrValues = $input->getOption(self::OPTION_ATTR_VALUE);
230
231
        for ($count = 0;; $count++) {
232
            $attrKey = $inputReader->readInput(
233
                '',
234
                Helper\QuestionFactory::createQuestion('Add an attribute (empty to skip)', $attrKeys[$count] ?? ''),
235
                new Validator\StringValidator()
236
            );
237
238
            if (!$attrKey) {
239
                break;
240
            }
241
242
            $attributes[$attrKey] = $inputReader->readInput(
243
                '',
244
                Helper\QuestionFactory::createQuestion('Value', $attrValues[$count] ?? ''),
245
                new Validator\StringValidator()
246
            );
247
        }
248
249
        $this->commandBus->handle(
250
            new AddDonor(new NewDonor($mandateSource, $payerNumber, $account, $donorId, $donationAmount))
251
        );
252
253
        $donor = $this->donorRepository->requireByPayerNumber($payerNumber);
254
255
        $this->commandBus->handle(new UpdateState($donor, NewMandate::getStateId(), 'Mandate added manually'));
256
257
        $this->commandBus->handle(new UpdateName($donor, $name));
258
259
        $this->commandBus->handle(new UpdatePostalAddress($donor, $postalAddress));
260
261
        $this->commandBus->handle(new UpdateEmail($donor, $email));
262
263
        $this->commandBus->handle(new UpdatePhone($donor, $phone));
264
265
        $this->commandBus->handle(new UpdateComment($donor, $comment));
266
267
        foreach ($attributes as $attrKey => $attrValue) {
268
            $this->commandBus->handle(new UpdateAttribute($donor, $attrKey, $attrValue));
269
        }
270
271
        $this->evaluateDryRun($input);
272
    }
273
}
274