EuInstallCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 9
dl 0
loc 12
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gewebe\SyliusVATPlugin\Command;
6
7
use Gewebe\SyliusVATPlugin\Vat\Rates\RatesInterface;
8
use Sylius\Component\Addressing\Factory\ZoneFactory;
9
use Sylius\Component\Addressing\Model\CountryInterface;
10
use Sylius\Component\Addressing\Model\ZoneInterface;
11
use Sylius\Component\Core\Model\Scope;
12
use Sylius\Component\Core\Model\TaxRateInterface;
13
use Sylius\Component\Resource\Factory\FactoryInterface;
14
use Sylius\Component\Resource\Repository\RepositoryInterface;
15
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Input\InputArgument;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Input\InputOption;
20
use Symfony\Component\Console\Output\OutputInterface;
21
22
/**
23
 * Install EU countries, zones and VAT rates to Sylius
24
 *
25
 *  @Todo: rewrite setup of different tax schemas
26
 */
27
final class EuInstallCommand extends Command
28
{
29
    public function __construct(
30
        private RatesInterface $vatRates,
31
        private FactoryInterface $countryFactory,
32
        private RepositoryInterface $countryRepository,
33
        private ZoneFactory $zoneFactory,
34
        private RepositoryInterface $zoneRepository,
35
        private FactoryInterface $taxRateFactory,
36
        private RepositoryInterface $taxRateRepository,
37
        private FactoryInterface $taxCategoryFactory,
38
        private RepositoryInterface $taxCategoryRepository,
39
    ) {
40
        parent::__construct();
41
    }
42
43
    protected function configure(): void
44
    {
45
        $this
46
            ->setName('vat:install:eu')
47
            ->setDescription('Install European countries, zones and VAT rates')
48
            ->addArgument(
49
                'country',
50
                InputArgument::OPTIONAL,
51
                'Domestic Country',
52
            )
53
            ->addOption(
54
                'categories',
55
                'c',
56
                InputOption::VALUE_REQUIRED,
57
                'Tax categories, e.g.: standard,reduced',
58
                'standard',
59
            )
60
            ->addOption(
61
                'included',
62
                'i',
63
                InputOption::VALUE_NONE,
64
                'Tax rate is included in price',
65
            )
66
            ->addOption(
67
                'threshold',
68
                't',
69
                InputOption::VALUE_REQUIRED,
70
                'Threshold Countries',
71
                '',
72
            )
73
        ;
74
    }
75
76
    private function getArgumentCountry(InputInterface $input): string
77
    {
78
        /** @var string $country */
79
        $country = $input->getArgument('country') ?? '';
80
81
        return strtolower($country);
82
    }
83
84
    /**
85
     * @return string[]
86
     */
87
    private function getOptionCategories(InputInterface $input): array
88
    {
89
        /** @var string $categories */
90
        $categories = $input->getOption('categories') ?? '';
91
92
        return explode(',', $categories);
93
    }
94
95
    private function getOptionIncluded(InputInterface $input): bool
96
    {
97
        return $input->getOption('included') === true;
98
    }
99
100
    private function getOptionThreshold(InputInterface $input): array
101
    {
102
        /** @var string $threshold */
103
        $threshold = $input->getOption('threshold') ?? '';
104
105
        return explode(',', strtolower($threshold));
106
    }
107
108
    protected function execute(InputInterface $input, OutputInterface $output): int
109
    {
110
        $baseCountry = $this->getArgumentCountry($input);
111
112
        $thresholdCountries = $this->getOptionThreshold($input);
113
114
        $taxCategories = $this->getOptionCategories($input);
115
        foreach ($taxCategories as $taxCategory) {
116
            $this->addTaxCategory($taxCategory);
117
        }
118
119
        $euZones = [];
120
        foreach ($this->vatRates->getCountries() as $countryCode => $countryName) {
121
            $output->writeln('Install: ' . $countryCode);
122
123
            $country = $this->addCountry(strtoupper($countryCode));
124
125
            $zone = $this->addZone(
126
                strtoupper($countryCode) . '-vat',
127
                $countryName . ' VAT',
128
                [$country->getCode()],
129
                ZoneInterface::TYPE_COUNTRY,
130
            );
131
132
            $euZones[] = $zone->getCode();
133
134
            if (in_array(strtolower($countryCode), $thresholdCountries, true)) {
135
                $zone = $this->addZone(
136
                    $countryCode . '-tax',
137
                    $countryName . ' Tax',
138
                    [$country->getCode()],
139
                    ZoneInterface::TYPE_COUNTRY,
140
                    Scope::TAX,
141
                );
142
            } elseif (strlen($baseCountry) > 0) {
143
                continue;
144
            }
145
146
            foreach ($taxCategories as $taxCategory) {
147
                $this->addTaxRate(
148
                    $countryCode,
149
                    $countryCode,
150
                    $taxCategory,
151
                    $zone,
152
                    $this->getOptionIncluded($input),
153
                );
154
            }
155
        }
156
157
        $output->writeln('Install: EU');
158
        $zone = $this->addZone(
159
            'EU',
160
            'European Union VAT',
161
            $euZones,
162
            ZoneInterface::TYPE_ZONE,
163
        );
164
165
        if (strlen($baseCountry) > 0) {
166
            foreach ($taxCategories as $taxCategory) {
167
                $this->addTaxRate(
168
                    $baseCountry,
169
                    'eu',
170
                    $taxCategory,
171
                    $zone,
172
                    $this->getOptionIncluded($input),
173
                );
174
            }
175
        }
176
177
        return 0;
178
    }
179
180
    private function addCountry(string $code): CountryInterface
181
    {
182
        /** @var CountryInterface|null $country */
183
        $country = $this->countryRepository->findOneBy(['code' => $code]);
184
        if ($country instanceof CountryInterface) {
185
            return $country;
186
        }
187
188
        /** @var CountryInterface $country */
189
        $country = $this->countryFactory->createNew();
190
        $country->setCode($code);
191
192
        $this->countryRepository->add($country);
193
194
        return $country;
195
    }
196
197
    private function addZone(string $code, string $name, array $countries, string $type, string $scope = Scope::ALL): ZoneInterface
198
    {
199
        /** @var ZoneInterface|null $zone */
200
        $zone = $this->zoneRepository->findOneBy(['code' => $code, 'type' => $type]);
201
        if ($zone instanceof ZoneInterface) {
202
            return $zone;
203
        }
204
205
        $zone = $this->zoneFactory->createWithMembers($countries);
206
        $zone->setCode($code);
207
        $zone->setName($name);
208
        $zone->setType($type);
209
        $zone->setScope($scope);
210
211
        $this->zoneRepository->add($zone);
212
213
        return $zone;
214
    }
215
216
    private function addTaxCategory(string $name): TaxCategoryInterface
217
    {
218
        /** @var TaxCategoryInterface|null $taxCategory */
219
        $taxCategory = $this->taxCategoryRepository->findOneBy(['code' => strtolower($name)]);
220
        if ($taxCategory instanceof TaxCategoryInterface) {
221
            return $taxCategory;
222
        }
223
224
        /** @var TaxCategoryInterface $taxCategory */
225
        $taxCategory = $this->taxCategoryFactory->createNew();
226
        $taxCategory->setCode(strtolower($name));
227
        $taxCategory->setName(ucfirst($name));
228
229
        $this->taxCategoryRepository->add($taxCategory);
230
231
        return $taxCategory;
232
    }
233
234
    private function addTaxRate(
235
        string $country,
236
        string $code,
237
        string $category,
238
        ZoneInterface $zone,
239
        bool $includedInPrice = false,
240
    ): void {
241
        try {
242
            $countryRate = $this->vatRates->getCountryRate(strtoupper($country), $category) / 100;
243
        } catch (\Exception $e) {
244
            return;
245
        }
246
247
        /** @var TaxRateInterface|null $taxRate */
248
        $taxRate = $this->taxRateRepository->findOneBy(['code' => strtolower($code) . '-' . $category]);
249
        if ($taxRate instanceof TaxRateInterface) {
250
            if ($taxRate->getAmount() !== $countryRate) {
251
                $taxRate->setAmount($countryRate);
252
253
                $this->taxRateRepository->add($taxRate);
254
            }
255
256
            return;
257
        }
258
259
        /** @var TaxCategoryInterface $taxCategory */
260
        $taxCategory = $this->taxCategoryRepository->findOneBy(['code' => $category]);
261
262
        /** @var TaxRateInterface $taxRate */
263
        $taxRate = $this->taxRateFactory->createNew();
264
        $taxRate->setCode(strtolower($code . '-' . $category));
265
        $taxRate->setName('VAT');
266
        $taxRate->setAmount($countryRate);
267
        $taxRate->setCalculator('default');
268
        $taxRate->setIncludedInPrice($includedInPrice);
269
        $taxRate->setZone($zone);
270
        $taxRate->setCategory($taxCategory);
271
272
        $this->taxRateRepository->add($taxRate);
273
    }
274
}
275