Completed
Push — master ( cf71fc...f80427 )
by Bram
02:23
created

Reservation::createReservationCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Reservation.php
4
 *
5
 * @author Bram de Leeuw
6
 * Date: 09/03/17
7
 */
8
9
namespace Broarm\EventTickets;
10
11
use CalendarEvent;
12
use CalendarEvent_Controller;
13
use DataObject;
14
use Director;
15
use Dompdf\Dompdf;
16
use FieldList;
17
use File;
18
use Folder;
19
use GridField;
20
use GridFieldConfig_RecordViewer;
21
use HasManyList;
22
use ManyManyList;
23
use Member;
24
use ReadonlyField;
25
use SilverStripe\Omnipay\GatewayInfo;
26
use SiteConfig;
27
use SSViewer;
28
use Tab;
29
use TabSet;
30
use ViewableData;
31
32
/**
33
 * Class Reservation
34
 *
35
 * @package Broarm\EventTickets
36
 *
37
 * @property string Status
38
 * @property string Title
39
 * @property float  Subtotal
40
 * @property float  Total
41
 * @property string Email todo determine obsolete value
42
 * @property string Comments
43
 * @property string ReservationCode
44
 * @property string Gateway
45
 *
46
 * @property int    EventID
47
 * @property int    MainContactID
48
 *
49
 * @method CalendarEvent|TicketExtension Event()
50
 * @method Attendee MainContact()
51
 * @method HasManyList Payments()
52
 * @method HasManyList Attendees()
53
 * @method ManyManyList PriceModifiers()
54
 */
55
class Reservation extends DataObject
56
{
57
    /**
58
     * Time to wait before deleting the discarded cart
59
     * Give a string that is parsable by strtotime
60
     *
61
     * @var string
62
     */
63
    private static $delete_after = '+1 day';
1 ignored issue
show
Unused Code introduced by
The property $delete_after is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
64
65
    private static $db = array(
2 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
66
        'Status' => 'Enum("CART,PENDING,PAID,CANCELED","CART")',
67
        'Title' => 'Varchar(255)',
68
        'Subtotal' => 'Currency',
69
        'Total' => 'Currency',
70
        'Email' => 'Varchar(255)',
71
        'Gateway' => 'Varchar(255)',
72
        'Comments' => 'Text',
73
        'ReservationCode' => 'Varchar(255)'
74
    );
75
76
    private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
77
        'Event' => 'CalendarEvent',
78
        'MainContact' => 'Broarm\EventTickets\Attendee'
79
    );
80
81
    private static $has_many = array(
2 ignored issues
show
Unused Code introduced by
The property $has_many is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
82
        'Payments' => 'Payment',
83
        'Attendees' => 'Broarm\EventTickets\Attendee.Reservation'
84
    );
85
86
    private static $belongs_many_many = array(
2 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $belongs_many_many is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
87
        'PriceModifiers' => 'Broarm\EventTickets\PriceModifier'
88
    );
89
90
    private static $indexes = array(
2 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $indexes is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
91
        'ReservationCode' => 'unique("ReservationCode")'
92
    );
93
94
    private static $summary_fields = array(
2 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $summary_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
95
        'ReservationCode' => 'Reservation',
96
        'Title' => 'Customer',
97
        'Total.Nice' => 'Total',
98
        'State' => 'Status',
99
        'GatewayNice' => 'Payment method',
100
        'Created.Nice' => 'Date'
101
    );
102
103
    public function getCMSFields()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
104
    {
105
        $fields = new FieldList(new TabSet('Root', $mainTab = new Tab('Main')));
106
        $gridFieldConfig = GridFieldConfig_RecordViewer::create();
107
        $fields->addFieldsToTab('Root.Main', array(
108
            ReadonlyField::create('ReservationCode', _t('Reservation.Code', 'Code')),
109
            ReadonlyField::create('Title', _t('Reservation.MainContact', 'Main contact')),
110
            ReadonlyField::create('GateWayNice', _t('Reservation.Gateway', 'Gateway')),
111
            ReadonlyField::create('Total', _t('Reservation.Total', 'Total')),
112
            ReadonlyField::create('Comments', _t('Reservation.Comments', 'Comments')),
113
            GridField::create('Attendees', 'Attendees', $this->Attendees(), $gridFieldConfig),
114
            GridField::create('Payments', 'Payments', $this->Payments(), $gridFieldConfig)
115
        ));
116
        $fields->addFieldsToTab('Root.Main', array());
117
        $this->extend('updateCMSFields', $fields);
118
        return $fields;
119
    }
120
121
    public function onBeforeWrite()
122
    {
123
        // Set the title to the name of the reservation holder
124
        $this->Title = $this->getName();
125
126
        // Create a validation code to be used for confirmation and in the barcode
127
        if ($this->exists() && empty($this->ReservationCode)) {
128
            $this->ReservationCode = $this->createReservationCode();
129
        }
130
131
        parent::onBeforeWrite();
132
    }
133
134
    public function onBeforeDelete()
135
    {
136
        // If a reservation is deleted remove the names from the guest list
137
        foreach ($this->Attendees() as $attendee) {
138
            /** @var Attendee $attendee */
139
            if ($attendee->exists()) {
140
                $attendee->delete();
141
            }
142
        }
143
144
        // Remove the folder
145
        if ($this->fileFolder()->exists()) {
146
            $this->fileFolder()->delete();
147
        }
148
149
        parent::onBeforeDelete();
150
    }
151
152
    /**
153
     * Gets a nice unnamespaced name
154
     *
155
     * @return string
156
     */
157
    public function singular_name()
158
    {
159
        $name = explode('\\', parent::singular_name());
160
        return trim(end($name));
161
    }
162
163
    /**
164
     * Returns the nice gateway title
165
     *
166
     * @return string
167
     */
168
    public function getGatewayNice() {
169
        return GatewayInfo::niceTitle($this->Gateway);
170
    }
171
172
    /**
173
     * Check if the cart is still in cart state and the delete_after time period has been exceeded
174
     *
175
     * @return bool
176
     */
177
    public function isDiscarded()
178
    {
179
        $deleteAfter = strtotime(self::config()->get('delete_after'), strtotime($this->Created));
180
        return ($this->Status === 'CART') && (time() > $deleteAfter);
181
    }
182
183
    /**
184
     * Get the full name
185
     *
186
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
187
     */
188
    public function getName()
189
    {
190
        /** @var Attendee $attendee */
191
        if ($this->MainContact()->exists()) {
192
            return $this->MainContact()->getName();
193
        } else {
194
            return 'new reservation';
195
        }
196
    }
197
198
    /**
199
     * Return the translated state
200
     * @return string
201
     */
202
    public function getState()
203
    {
204
        return _t("Reservation.{$this->Status}", $this->Status);
205
    }
206
207
    /**
208
     * Get the total by querying the sum of attendee ticket prices
209
     *
210
     * @return float
211
     */
212
    public function calculateTotal()
213
    {
214
        $total = $this->Subtotal = $this->Attendees()->leftJoin(
215
            'Broarm\EventTickets\Ticket',
216
            '`Broarm\EventTickets\Attendee`.`TicketID` = `Broarm\EventTickets\Ticket`.`ID`'
217
        )->sum('Price');
218
219
        // Calculate any price modifications if added
220
        if ($this->PriceModifiers()->exists()) {
221
            foreach ($this->PriceModifiers() as $priceModifier) {
222
                $priceModifier->updateTotal($total);
223
            }
224
        }
225
226
        return $this->Total = $total;
227
    }
228
229
    /**
230
     * Safely change to a state
231
     *
232
     * @param $state
233
     */
234
    public function changeState($state)
235
    {
236
        $availableStates = $this->dbObject('Status')->enumValues();
237
        if (in_array($state, $availableStates)) {
238
            $this->Status = $state;
239
        } else {
240
            user_error(_t('Reservation.STATE_CHANGE_ERROR', 'Selected state is not available'));
241
        }
242
    }
243
244
    /**
245
     * Set the main contact id
246
     *
247
     * @param $id
248
     */
249
    public function setMainContact($id) {
250
        $this->MainContactID = $id;
251
        $this->write();
252
    }
253
254
    /**
255
     * Create a reservation code
256
     *
257
     * @return string
258
     */
259
    public function createReservationCode()
260
    {
261
        return uniqid($this->ID);
262
    }
263
264
    /**
265
     * Create the folder for the qr code and ticket file
266
     *
267
     * @return Folder|DataObject|null
268
     */
269
    public function fileFolder()
270
    {
271
        return Folder::find_or_make("/event-tickets/{$this->ReservationCode}/");
272
    }
273
274
    /**
275
     * Generate the qr codes and downloadable pdf
276
     */
277
    public function createFiles()
278
    {
279
        $folder = $this->fileFolder();
280
        /** @var Attendee $attendee */
281
        foreach ($this->Attendees() as $attendee) {
282
            $attendee->createQRCode($folder);
283
            $attendee->createTicketFile($folder);
284
        }
285
    }
286
287
    public function canView($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
288
    {
289
        return $this->Event()->canView($member);
290
    }
291
292
    public function canEdit($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
293
    {
294
        return $this->Event()->canEdit($member);
1 ignored issue
show
Bug introduced by
The method canEdit does only exist in Broarm\EventTickets\TicketExtension, but not in CalendarEvent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
295
    }
296
297
    public function canDelete($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
298
    {
299
        return $this->Event()->canDelete($member);
1 ignored issue
show
Bug introduced by
The method canDelete does only exist in Broarm\EventTickets\TicketExtension, but not in CalendarEvent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
300
    }
301
302
    public function canCreate($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
303
    {
304
        return $this->Event()->canCreate($member);
1 ignored issue
show
Bug introduced by
The method canCreate does only exist in Broarm\EventTickets\TicketExtension, but not in CalendarEvent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
305
    }
306
}
307