Passed
Push — master ( 7264d5...1976a0 )
by Chris
32s
created

Configuration::getTaxRate()   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\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
            $instance->discountCodes[$identifier] = new DiscountCode(
150
                $identifier,
151
                $code['name'],
152
                $discountType
153
            );
154
        }
155
156
        return $instance;
157
    }
158
159
    /**
160
     * @param $ticket
161
     * @param $identifier
162
     */
163
    private function addTicketInformation(array $ticket, string $identifier)
164
    {
165
        $price = Price::fromNetCost(
166
            new Money($ticket['cost'], $this->currency),
167
            $this->taxRate
168
        );
169
170
        $this->ticketTypes[$identifier] = new TicketType(
171
            $identifier,
172
            $price,
173
            $ticket['name'],
174
            $ticket['description'] ?? ''
175
        );
176
177
        $this->avaliableTickets[$identifier] = $ticket['available'];
178
179
        $this->ticketMetadata[$identifier] = TicketMetadata::fromArray(
180
            $this->ticketTypes[$identifier],
181
            $ticket['metadata'] ?? []
182
        );
183
    }
184
185
    /**
186
     * @return string
187
     */
188 10
    public function getCurrency(): string
189
    {
190 10
        return $this->currency;
191
    }
192
193
    /**
194
     * @return TaxRate
195
     */
196 10
    public function getTaxRate(): TaxRate
197
    {
198 10
        return $this->taxRate;
199
    }
200
201
    /**
202
     * @return boolean
203
     */
204
    public function displayTax(): bool
205
    {
206
        return $this->displayTax;
207
    }
208
209
    /**
210
     * @return TicketType[]
211
     */
212
    public function getTicketTypes(): array
213
    {
214
        return $this->ticketTypes;
215
    }
216
217
    /**
218
     * @return TicketType
219
     */
220
    public function getTicketType(string $identifier): TicketType
221
    {
222
        return $this->ticketTypes[$identifier];
223
    }
224
225
    /**
226
     * @param string $identifier
227
     * @return int
228
     */
229
    public function getAvailableTickets(string $identifier): int
230
    {
231
        return $this->avaliableTickets[$identifier];
232
    }
233
234
    public function getDiscountCodes(): array
235
    {
236
        return $this->discountCodes;
237
    }
238
239 4
    public function getTicketMetadata(string $identifier): TicketMetadata
240
    {
241 4
        return $this->ticketMetadata[$identifier];
242
    }
243
}