Passed
Pull Request — master (#71)
by Chris
03:21
created

Configuration   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 247
Duplicated Lines 0 %

Test Coverage

Coverage 14.55%

Importance

Changes 0
Metric Value
dl 0
loc 247
ccs 8
cts 55
cp 0.1455
rs 10
c 0
b 0
f 0
wmc 18

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 1 1
A getTicketMetadata() 0 3 1
A getCurrency() 0 3 1
A getTaxRate() 0 3 1
A displayTax() 0 3 1
A getTicketTypes() 0 3 1
A getAvailableTickets() 0 3 1
B addTicketInformation() 0 28 4
A getTicketType() 0 3 1
B fromArray() 0 34 5
A getDiscountCodes() 0 3 1
1
<?php
2
3
namespace ConferenceTools\Tickets\Domain\Service;
4
5
use ConferenceTools\Tickets\Domain\ValueObject\DiscountCode;
6
use ConferenceTools\Tickets\Domain\ValueObject\Money;
7
use ConferenceTools\Tickets\Domain\ValueObject\Price;
8
use ConferenceTools\Tickets\Domain\ValueObject\TaxRate;
9
use ConferenceTools\Tickets\Domain\ValueObject\TicketMetadata;
10
use ConferenceTools\Tickets\Domain\ValueObject\TicketType;
11
use Zend\Stdlib\ArrayUtils;
12
13
class Configuration
14
{
15
    //@TODO change to private const
16
    private static $defaults = [
17
        'tickets' => [],
18
        'discountCodes' => [],
19
        'financial' => [
20
            'currency' => 'GBP',
21
            'taxRate' => 0,
22
            'displayTax' => false
23
        ]
24
    ];
25
26
    /**
27
     * Defines the currency in use across the app.
28
     *
29
     * Defaults to GBP, should be a proper currency code otherwise you will have issues with display of
30
     * currency values and creating stripe charges.
31
     *
32
     * config key: financial->currency
33
     *
34
     * @var string
35
     */
36
    private $currency;
37
38
    /**
39
     * The tax rate in use across the app.
40
     *
41
     * Defaults to 0% Will be added to all cost values for tickets. The app assumes a single tax rate for all tickets
42
     * and also assumes that tickets are for a physical event. As such the EU VATMOSS rules do not apply. If you are
43
     * selling tickets for a webinar or online conference, you should check with legal advisers if this is appropriate.
44
     *
45
     * config key: financial->taxRate
46
     *
47
     * @var TaxRate
48
     */
49
    private $taxRate;
50
51
    /**
52
     * Should VAT/sales tax be displayed in the app.
53
     *
54
     * Defaults to false. If enabled, this will display sales tax (VAT) in various points in the purchase process. You
55
     * should also update the layout template to include the relevent legal information. There are three ways this app
56
     * can deal with tax:
57
     * - if you are not vat registered or do not need to charge VAT, you can set this to false and the tax rate to 0;
58
     *   the app will not track any tax for you.
59
     * - if you set a tax rate but disable this flag, VAT will be added to purchases and tracked by the app but not
60
     *   made visible to customers. The main purpose of this is for when you have a pending VAT registration; the app
61
     *   will still track the tax and you can turn on the display of this tracking when the registration completes.
62
     *   Another use for this, if you don't need to track VAT would be to add a handling/processing fee to tickets.
63
     * - If you set a tax rate and enable this flag, VAT will be tracked and displayed to your customers at purchase
64
     *   time.
65
     *
66
     *
67
     * config key: financial->displayTax
68
     *
69
     * @var bool
70
     */
71
    private $displayTax;
72
73
    /**
74
     * An array of available ticket types. The app uses this for determining how many tickets are available and their
75
     * prices.
76
     *
77
     * If you change this config, you will need to rebuild the ticket counters projection to get the updated types in
78
     * your app.
79
     *
80
     * config key: tickets
81
     * structure: identifier => [
82
     *      'cost' => Net cost in pence/cents (eg before tax price),
83
     *      'name' => display name shown to customers,
84
     *      'available' => Number available for purchase
85
     * ]
86
     *
87
     * @var TicketType[]
88
     */
89
    private $ticketTypes;
90
91
    /**
92
     * Holds a count of avaliable tickets by type.
93
     *
94
     * @see ticketTypes for how to configure
95
     *
96
     * @var int[]
97
     */
98
    private $avaliableTickets;
99
100
    /**
101
     * An array of discount codes. The app uses this for validating and applying different codes.
102
     *
103
     * If you change this config, you will need to rebuild the discount codes projection
104
     *
105
     * configkey: discountCodes
106
     * structure: identifier => [
107
     *      'type' => The class name of the discount type eg Percentage::class,
108
     *      'name' => User friendly name for the code
109
     *      'options' => An array of options for the type you are using
110
     * ]
111
     *
112
     * @var DiscountCode[]
113
     */
114
    private $discountCodes;
115
116
    /**
117
     * Contains metadata about tickets eg when they are available for sale
118
     *
119
     * configkey: tickets->metadata
120
     * structure: [
121
     *      'availableFrom' => DateTime ticket is to go on sale from,
122
     *      'availableTo' => DateTime after which ticket is no longer on sale
123
     * ]
124
     *
125
     * @var TicketMetadata[]
126
     */
127
    private $ticketMetadata;
128
129
    private function __construct() {}
130
131
    public static function fromArray(array $settings)
132
    {
133
        /** Ensures that all the keys exist @TODO remove dependency on Zend Array Utils for this */
134
        $settings = ArrayUtils::merge(self::$defaults, $settings);
135
        $instance = new static();
136
137
        $instance->currency = (string) $settings['financial']['currency'];
138
        $instance->displayTax = (string) $settings['financial']['displayTax'];
0 ignored issues
show
Documentation Bug introduced by
The property $displayTax was declared of type boolean, but (string)$settings['financial']['displayTax'] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
139
        $instance->taxRate = new TaxRate($settings['financial']['taxRate']);
140
141
        foreach ($settings['tickets'] as $identifier => $ticket) {
142
            $instance->addTicketInformation($ticket, $identifier);
143
        }
144
145
        foreach ($settings['discountCodes'] as $identifier => $code) {
146
            // Be careful here; configuration object is still under constrcution at the time it is passed in
147
            // Might need to rethink this at some point
148
            $discountType = call_user_func([$code['type'], 'fromArray'], $code['options'], $instance);
149
            $discountCode = new DiscountCode(
150
                $identifier,
151
                $code['name'],
152
                $discountType
153
            );
154
155
            $instance->discountCodes[$identifier] = $discountCode;
156
157
            if (isset($code['additionalCodes'])) {
158
                foreach ((array) $code['additionalCodes'] as $additionalCode) {
159
                    $instance->discountCodes[$additionalCode] = $discountCode;
160
                }
161
            }
162
        }
163
164
        return $instance;
165
    }
166
167
    /**
168
     * @param $ticket
169
     * @param $identifier
170
     */
171
    private function addTicketInformation(array $ticket, string $identifier)
172
    {
173
        $price = Price::fromNetCost(
174
            new Money($ticket['cost'], $this->currency),
175
            $this->taxRate
176
        );
177
178
        $this->ticketTypes[$identifier] = new TicketType(
179
            $identifier,
180
            $price,
181
            $ticket['name']
182
        );
183
184
        $this->avaliableTickets[$identifier] = $ticket['available'];
185
186
        $ticket['metadata'] = ArrayUtils::merge(['private' => false], (isset($ticket['metadata']) ? $ticket['metadata'] : []));
187
188
        if (isset($ticket['metadata']['availableFrom']) && isset($ticket['metadata']['availableTo'])) {
189
            $this->ticketMetadata[$identifier] = new TicketMetadata(
190
                $this->ticketTypes[$identifier],
191
                $ticket['metadata']['availableFrom'],
192
                $ticket['metadata']['availableTo'],
193
                $ticket['metadata']['private']
194
            );
195
        } else {
196
            $this->ticketMetadata[$identifier] = TicketMetadata::createWithoutDates(
197
                $this->ticketTypes[$identifier],
198
                $ticket['metadata']['private']
199
            );
200
        }
201
    }
202
203
    /**
204
     * @return string
205
     */
206 6
    public function getCurrency(): string
207
    {
208 6
        return $this->currency;
209
    }
210
211
    /**
212
     * @return TaxRate
213
     */
214 6
    public function getTaxRate(): TaxRate
215
    {
216 6
        return $this->taxRate;
217
    }
218
219
    /**
220
     * @return boolean
221
     */
222
    public function displayTax(): bool
223
    {
224
        return $this->displayTax;
225
    }
226
227
    /**
228
     * @return TicketType[]
229
     */
230 4
    public function getTicketTypes(): array
231
    {
232 4
        return $this->ticketTypes;
233
    }
234
235
    /**
236
     * @return TicketType
237
     */
238
    public function getTicketType(string $identifier): TicketType
239
    {
240
        return $this->ticketTypes[$identifier];
241
    }
242
243
    /**
244
     * @param string $identifier
245
     * @return int
246
     */
247
    public function getAvailableTickets(string $identifier): int
248
    {
249
        return $this->avaliableTickets[$identifier];
250
    }
251
252
    public function getDiscountCodes(): array
253
    {
254
        return $this->discountCodes;
255
    }
256
257 4
    public function getTicketMetadata(string $identifier): TicketMetadata
258
    {
259 4
        return $this->ticketMetadata[$identifier];
260
    }
261
}