Completed
Push — master ( e4e633...87cf18 )
by Bram
02:22
created

Discount::validateUses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Discount.php
4
 *
5
 * @author Bram de Leeuw
6
 * Date: 30/03/17
7
 */
8
9
namespace Broarm\EventTickets;
10
11
use CalendarEvent;
12
use Currency;
13
use DateField;
14
use DropdownField;
15
use Group;
16
use ManyManyList;
17
use Member;
18
use NumericField;
19
use ReadonlyField;
20
use SS_Datetime;
21
use TagField;
22
23
/**
24
 * Class Discount
25
 *
26
 * @property string Code
27
 * @property string ValidFrom
28
 * @property string ValidTill
29
 * @property float  Amount
30
 * @property int    Uses
31
 * @property bool   Used
32
 * @property string DiscountType
33
 * @method ManyManyList Groups()
34
 * @method ManyManyList Events()
35
 * @method ManyManyList Reservations()
36
 */
37
class Discount extends PriceModifier
38
{
39
    const PRICE = 'PRICE';
40
    const PERCENTAGE = 'PERCENTAGE';
41
42
    private static $singular_name = 'Discount';
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 $singular_name 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...
43
44
    private static $db = 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 $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...
45
        'Amount' => 'Decimal',
46
        'Uses' => 'Int',
47
        'DiscountType' => 'Enum("PRICE,PERCENTAGE","PRICE")',
48
        'Code' => 'Varchar(255)',
49
        'ValidFrom' => 'SS_Datetime',
50
        'ValidTill' => 'SS_Datetime'
51
    );
52
53
    private static $default_sort = "ValidFrom DESC";
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 $default_sort 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...
54
55
    private static $many_many = 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 $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...
56
        'Groups' => 'Group',
57
        'Events' => 'CalendarEvent'
58
    );
59
60
    private static $indexes = 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 $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...
61
        'Code' => 'unique("Code")'
62
    );
63
64
    private static $summary_fields = 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 $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...
65
        'Code' => 'Code',
66
        'ValidFrom.Nice' => 'Valid from',
67
        'ValidTill.Nice' => 'Valid till',
68
        'Reservations.Count' => 'Uses'
69
    );
70
71
    private static $defaults = 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 $defaults 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...
72
        'Uses' => 1
73
    );
74
75
    /**
76
     * Create the needed cms fields
77
     *
78
     * @return \FieldList
79
     */
80
    public function getCMSFields()
81
    {
82
        $fields = parent::getCMSFields();
83
84
        $types = $this->dbObject('DiscountType')->enumValues();
85
86
        $fields->addFieldsToTab('Root.Main', array(
87
            $code = ReadonlyField::create('Code', 'Code'),
88
            DropdownField::create('DiscountType', _t('Discount.TYPE', 'Type of discount'), $types),
89
            NumericField::create('Amount', _t('Discount.AMOUNT', 'Amount')),
90
            NumericField::create('Uses', _t('Discount.USES', 'Maximum number of uses')),
91
            $validFrom = DateField::create('ValidFrom', _t('Discount.VALID_FROM', 'Valid from')),
92
            $validTill = DateField::create('ValidTill', _t('Discount.VALID_TILL', 'Valid till')),
93
            TagField::create('Groups', _t('Discount.GROUPS', 'Constrain to groups'), Group::get()),
94
            TagField::create('Events', _t('Discount.EVENTS', 'Constrain to events'), CalendarEvent::get())
95
        ));
96
97
        $code->setDescription(
98
            _t('Discount.CODE_HELP', 'The code is generated after saving')
99
        );
100
101
        $validFrom
102
            ->setConfig('showcalendar', true)
103
            ->setDescription(_t('Discount.VALID_FROM_HELP', 'If no date is set the current date is used'));
104
        $validTill
105
            ->setConfig('showcalendar', true)
106
            ->setDescription(_t('Discount.VALID_TILL_HELP', 'If no date is set the current date + 1 year is used'));
107
108
        $fields->removeByName(array('Title'));
109
        return $fields;
110
    }
111
112
    public function onBeforeWrite()
113
    {
114
        if (empty($this->Code)) {
115
            $this->Code = $this->generateCode();
116
            $this->Title = $this->Code;
117
        }
118
119
        if (empty($this->ValidFrom) && empty($this->ValidTill)) {
120
            $format = 'Y-m-d';
121
            $this->ValidFrom = $start = date($format);
122
            $this->ValidTill = date($format, strtotime("$start + 1 year"));
123
        }
124
125
        parent::onBeforeWrite();
126
    }
127
128
    /**
129
     * Return the table title
130
     *
131
     * @return string
132
     */
133
    public function getTableTitle()
134
    {
135
        return _t('Discount.DISCOUNT', 'Discount');
136
    }
137
138
    /**
139
     * Check if the discount exceeded the maximum uses
140
     *
141
     * @return bool
142
     */
143
    public function validateUses()
144
    {
145
        return $this->Reservations()->count() >= $this->Uses;
146
    }
147
148
    /**
149
     * Calculate the discount
150
     *
151
     * @param $total
152
     */
153
    public function updateTotal(&$total)
154
    {
155
        switch ($this->DiscountType) {
156
            case self::PERCENTAGE:
157
                $discount = ($total / 100 * $this->Amount);
158
                $total -= $discount;
159
                break;
160
            default: // case price
161
                $discount = $this->Amount;
162
                $total -= $discount;
163
                $total = $total > 0 ? $total : 0;
164
                break;
165
        }
166
167
        // save the modification on the join
168
        $this->setPriceModification($discount);
169
    }
170
171
    /**
172
     * Check if the from and till dates are in the past and future
173
     *
174
     * @return bool
175
     */
176
    public function validateDate()
177
    {
178
        /** @var SS_Datetime $from */
179
        $from = $this->dbObject('ValidFrom');
180
        /** @var SS_Datetime $till */
181
        $till = $this->dbObject('ValidTill');
182
183
        return (bool)($from->InPast() && $till->InFuture());
184
    }
185
186
    /**
187
     * Validate the given member with the allowed groups
188
     *
189
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be null|Member?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
190
     *
191
     * @return bool
192
     */
193
    public function validateGroups(Member $member = null)
194
    {
195
        // If groups are attached to the discount, check if valid
196
        if ($this->Groups()->exists()) {
197
            if (empty($member)) {
198
                return false;
199
            } else {
200
                $validGroups = $this->Groups()->column('ID');
201
                $groupMembers = Member::get()->filter('Groups.ID:ExactMatchMulti', $validGroups);
202
                return (bool)$groupMembers->find('ID', $member->ID);
203
            }
204
        }
205
206
        return true;
207
    }
208
209
    /**
210
     * Validate if the given event is in the group of allowed events
211
     *
212
     * @param CalendarEvent $event
213
     *
214
     * @return bool
215
     */
216
    public function validateEvents(CalendarEvent $event)
217
    {
218
        // If events are attached to the discount, check if valid
219
        if ($this->Events()->exists()) {
220
            if (empty($event)) {
221
                return false;
222
            } else {
223
                $validEvents = $this->Events()->column('ID');
224
                return in_array($event->ID, $validEvents);
225
            }
226
        }
227
228
        return true;
229
    }
230
231
    /**
232
     * Generate a unique coupon code
233
     *
234
     * @return string
235
     */
236
    public function generateCode()
237
    {
238
        return uniqid($this->ID);
239
    }
240
}
241