Passed
Push — master ( c87045...1efded )
by Chris
34s
created

Configuration::getDiscountCodes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace ConferenceTools\Tickets\Domain\Service;
4
5
use ConferenceTools\Tickets\Domain\ValueObject\DiscountCode;
6
use ConferenceTools\Tickets\Domain\ValueObject\DiscountCodeMetadata;
7
use ConferenceTools\Tickets\Domain\ValueObject\Money;
8
use ConferenceTools\Tickets\Domain\ValueObject\Price;
9
use ConferenceTools\Tickets\Domain\ValueObject\TaxRate;
10
use ConferenceTools\Tickets\Domain\ValueObject\TicketMetadata;
11
use ConferenceTools\Tickets\Domain\ValueObject\TicketType;
12
use Zend\Stdlib\ArrayUtils;
13
14
class Configuration
15
{
16
    //@TODO change to private const
17
    private static $defaults = [
18
        'tickets' => [],
19
        'discountCodes' => [],
20
        'financial' => [
21
            'currency' => 'GBP',
22
            'taxRate' => 0,
23
            'displayTax' => false
24
        ]
25
    ];
26
27
    /**
28
     * Defines the currency in use across the app.
29
     *
30
     * Defaults to GBP, should be a proper currency code otherwise you will have issues with display of
31
     * currency values and creating stripe charges.
32
     *
33
     * config key: financial->currency
34
     *
35
     * @var string
36
     */
37
    private $currency;
38
39
    /**
40
     * The tax rate in use across the app.
41
     *
42
     * Defaults to 0% Will be added to all cost values for tickets. The app assumes a single tax rate for all tickets
43
     * and also assumes that tickets are for a physical event. As such the EU VATMOSS rules do not apply. If you are
44
     * selling tickets for a webinar or online conference, you should check with legal advisers if this is appropriate.
45
     *
46
     * config key: financial->taxRate
47
     *
48
     * @var TaxRate
49
     */
50
    private $taxRate;
51
52
    /**
53
     * Should VAT/sales tax be displayed in the app.
54
     *
55
     * Defaults to false. If enabled, this will display sales tax (VAT) in various points in the purchase process. You
56
     * should also update the layout template to include the relevent legal information. There are three ways this app
57
     * can deal with tax:
58
     * - 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;
59
     *   the app will not track any tax for you.
60
     * - if you set a tax rate but disable this flag, VAT will be added to purchases and tracked by the app but not
61
     *   made visible to customers. The main purpose of this is for when you have a pending VAT registration; the app
62
     *   will still track the tax and you can turn on the display of this tracking when the registration completes.
63
     *   Another use for this, if you don't need to track VAT would be to add a handling/processing fee to tickets.
64
     * - If you set a tax rate and enable this flag, VAT will be tracked and displayed to your customers at purchase
65
     *   time.
66
     *
67
     *
68
     * config key: financial->displayTax
69
     *
70
     * @var bool
71
     */
72
    private $displayTax;
73
74
    /**
75
     * An array of available ticket types. The app uses this for determining how many tickets are available and their
76
     * prices.
77
     *
78
     * If you change this config, you will need to rebuild the ticket counters projection to get the updated types in
79
     * your app.
80
     *
81
     * config key: tickets
82
     * structure: identifier => [
83
     *      'cost' => Net cost in pence/cents (eg before tax price),
84
     *      'name' => display name shown to customers,
85
     *      'available' => Number available for purchase
86
     * ]
87
     *
88
     * @var TicketType[]
89
     */
90
    private $ticketTypes;
91
92
    /**
93
     * Holds a count of avaliable tickets by type.
94
     *
95
     * @see ticketTypes for how to configure
96
     *
97
     * @var int[]
98
     */
99
    private $avaliableTickets;
100
101
    /**
102
     * An array of discount codes. The app uses this for validating and applying different codes.
103
     *
104
     * If you change this config, you will need to rebuild the discount codes projection
105
     *
106
     * configkey: discountCodes
107
     * structure: identifier => [
108
     *      'type' => The class name of the discount type eg Percentage::class,
109
     *      'name' => User friendly name for the code
110
     *      'options' => An array of options for the type you are using
111
     * ]
112
     *
113
     * @var DiscountCode[]
114
     */
115
    private $discountCodes;
116
117
    /**
118
     * Contains metadata about tickets eg when they are available for sale
119
     *
120
     * configkey: tickets->metadata
121
     * structure: [
122
     *      'availableFrom' => DateTime ticket is to go on sale from,
123
     *      'availableTo' => DateTime after which ticket is no longer on sale
124
     * ]
125
     *
126
     * @var TicketMetadata[]
127
     */
128
    private $ticketMetadata;
129
130
    /**
131
     * Contains metadata about discount codes eg when they are available for use
132
     *
133
     * configkey: discountCodes->metadata
134
     * structure: [
135
     *     'availableFrom' => DateTime code can be used from,
136
     *     'availableTo' => DateTime code expires at
137
     * ]
138
     *
139
     * @var DiscountCodeMetadata[]
140
     */
141
    private $discountCodeMetadata;
142
143
    private function __construct() {}
144
145
    public static function fromArray(array $settings)
146
    {
147
        /** Ensures that all the keys exist @TODO remove dependency on Zend Array Utils for this */
148
        $settings = ArrayUtils::merge(self::$defaults, $settings);
149
        $instance = new static();
150
151
        $instance->currency = (string) $settings['financial']['currency'];
152
        $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...
153
        $instance->taxRate = new TaxRate($settings['financial']['taxRate']);
154
155
        foreach ($settings['tickets'] as $identifier => $ticket) {
156
            $instance->addTicketInformation($ticket, $identifier);
157
        }
158
159
        foreach ($settings['discountCodes'] as $identifier => $code) {
160
            $instance->addDiscountCodeInformation($code, $identifier);
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
            $ticket['description'] ?? ''
183
        );
184
185
        $this->avaliableTickets[$identifier] = $ticket['available'];
186
187
        $this->ticketMetadata[$identifier] = TicketMetadata::fromArray(
188
            $this->ticketTypes[$identifier],
189
            $ticket['metadata'] ?? []
190
        );
191
    }
192
193
    private function addDiscountCodeInformation(array $code, string $identifier)
194
    {
195
        // Be careful here; configuration object is still under constrcution at the time it is passed in
196
        // Might need to rethink this at some point
197
        $discountType = call_user_func([$code['type'], 'fromArray'], $code['options'], $this);
198
        $this->discountCodes[$identifier] = new DiscountCode(
199
            $identifier,
200
            $code['name'],
201
            $discountType
202
        );
203
204
        $this->discountCodeMetadata[$identifier] = DiscountCodeMetadata::fromArray(
205
            $this->discountCodes[$identifier],
206
            $code['metadata'] ?? []
207
        );
208
    }
209
210
    /**
211
     * @return string
212
     */
213 10
    public function getCurrency(): string
214
    {
215 10
        return $this->currency;
216
    }
217
218
    /**
219
     * @return TaxRate
220
     */
221 10
    public function getTaxRate(): TaxRate
222
    {
223 10
        return $this->taxRate;
224
    }
225
226
    /**
227
     * @return boolean
228
     */
229
    public function displayTax(): bool
230
    {
231
        return $this->displayTax;
232
    }
233
234
    /**
235
     * @return TicketType[]
236
     */
237
    public function getTicketTypes(): array
238
    {
239
        return $this->ticketTypes;
240
    }
241
242
    /**
243
     * @return TicketType
244
     */
245
    public function getTicketType(string $identifier): TicketType
246
    {
247
        return $this->ticketTypes[$identifier];
248
    }
249
250
    /**
251
     * @param string $identifier
252
     * @return int
253
     */
254
    public function getAvailableTickets(string $identifier): int
255
    {
256
        return $this->avaliableTickets[$identifier];
257
    }
258
259 4
    public function getDiscountCodes(): array
260
    {
261 4
        return $this->discountCodes;
262
    }
263
264 4
    public function getTicketMetadata(string $identifier): TicketMetadata
265
    {
266 4
        return $this->ticketMetadata[$identifier];
267
    }
268
269 4
    public function getDiscountCodeMetadata(string $code): DiscountCodeMetadata
270
    {
271 4
        return $this->discountCodeMetadata[$code];
272
    }
273
}