Passed
Push — master ( a55259...eb64b6 )
by Jason
02:28
created

Purchasable::getIsAvailable()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 5
nop 0
dl 0
loc 13
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
namespace Dynamic\Foxy\Extension;
4
5
use Dynamic\Foxy\Model\FoxyCategory;
6
use Dynamic\Foxy\Model\Variation;
7
use Dynamic\Foxy\Model\VariationType;
8
use micschk\GroupableGridfield\GridFieldGroupable;
9
use SilverStripe\Dev\Deprecation;
10
use SilverStripe\Forms\CheckboxField;
11
use SilverStripe\Forms\CurrencyField;
12
use SilverStripe\Forms\DropdownField;
13
use SilverStripe\Forms\FieldList;
14
use SilverStripe\Forms\GridField\GridField;
15
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
16
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
17
use SilverStripe\Forms\GridField\GridFieldPageCount;
18
use SilverStripe\Forms\GridField\GridFieldPaginator;
19
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
20
use SilverStripe\Forms\NumericField;
21
use SilverStripe\Forms\RequiredFields;
22
use SilverStripe\Forms\TextField;
23
use SilverStripe\ORM\DataExtension;
24
use SilverStripe\ORM\DataObject;
25
use SilverStripe\ORM\HasManyList;
26
use SilverStripe\Security\Permission;
27
use SilverStripe\Security\PermissionProvider;
28
use SilverStripe\Security\Security;
29
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
30
use Symbiote\GridFieldExtensions\GridFieldTitleHeader;
31
32
/**
33
 * Class Purchasable
34
 * @package Dynamic\Foxy\Extension
35
 *
36
 * @property double Price
37
 * @property string Code
38
 * @property string ReceiptTitle
39
 * @property bool Available
40
 * @property int $QuantityMax
41
 *
42
 * @property int FoxyCategoryID
43
 * @method FoxyCategory FoxyCategory()
44
 *
45
 * @method HasManyList Variations()
46
 *
47
 * @property-read DataObject|Purchasable $owner
48
 */
49
class Purchasable extends DataExtension implements PermissionProvider
50
{
51
    /**
52
     * @var array
53
     */
54
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
55
        'Price' => 'Currency',
56
        'Code' => 'Varchar(100)',
57
        'ReceiptTitle' => 'HTMLVarchar(255)',
58
        'Available' => 'Boolean',
59
        'QuantityMax' => 'Int',
60
    ];
61
62
    /**
63
     * @var array
64
     */
65
    private static $has_one = [
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
66
        'FoxyCategory' => FoxyCategory::class,
67
    ];
68
69
    /**
70
     * @var string[]
71
     */
72
    private static $has_many = [
0 ignored issues
show
introduced by
The private property $has_many is not used, and could be removed.
Loading history...
73
        'Variations' => Variation::class,
74
    ];
75
76
    /**
77
     * @var array
78
     */
79
    private static $indexes = [
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
80
        'Code' => [
81
            'type' => 'unique',
82
            'columns' => ['Code'],
83
        ],
84
    ];
85
86
    /**
87
     * @var array
88
     */
89
    private static $defaults = [
0 ignored issues
show
introduced by
The private property $defaults is not used, and could be removed.
Loading history...
90
        'ShowInMenus' => false,
91
        'Available' => true,
92
    ];
93
94
    /**
95
     * @var array
96
     */
97
    private static $summary_fields = [
0 ignored issues
show
introduced by
The private property $summary_fields is not used, and could be removed.
Loading history...
98
        'Image.CMSThumbnail',
99
        'Title',
100
        'Code',
101
        'Price.Nice',
102
    ];
103
104
    /**
105
     * @var array
106
     */
107
    private static $searchable_fields = [
0 ignored issues
show
introduced by
The private property $searchable_fields is not used, and could be removed.
Loading history...
108
        'Title',
109
        'Code',
110
        'Available',
111
    ];
112
113
    /**
114
     * @param array $labels
115
     */
116
    public function updateFieldLabels(&$labels)
117
    {
118
        $labels['Title'] = _t(__CLASS__ . '.TitleLabel', 'Product Name');
119
        $labels['Code'] = _t(__CLASS__ . '.CodeLabel', 'Code');
120
        $labels['Price'] = _t(__CLASS__ . '.PriceLabel', 'Price');
121
        $labels['Price.Nice'] = _t(__CLASS__ . '.PriceLabel', 'Price');
122
        $labels['Available'] = _t(__CLASS__ . '.AvailableLabel', 'Available for purchase');
123
        $labels['Available.Nice'] = _t(__CLASS__ . '.AvailableLabelNice', 'Available');
124
        $labels['Image.CMSThumbnail'] = _t(__CLASS__ . '.ImageLabel', 'Image');
125
        $labels['ReceiptTitle'] = _t(__CLASS__ . '.ReceiptTitleLabel', 'Product title for receipt');
126
        $labels['FoxyCategoryID'] = _t(__CLASS__ . '.FoxyCategoryLabel', 'Foxy Category');
127
    }
128
129
    /**
130
     * @param FieldList $fields
131
     */
132
    public function updateCMSFields(FieldList $fields)
133
    {
134
        $fields->removeByName([
135
            'SKU',
136
        ]);
137
138
        $fields->addFieldsToTab(
139
            'Root.Ecommerce',
140
            [
141
                CurrencyField::create('Price')
142
                    ->setDescription(_t(
143
                        __CLASS__ . '.PriceDescription',
144
                        'Base price for this product. Can be modified using Product variations'
145
                    )),
146
                TextField::create('Code')
147
                    ->setDescription(_t(
148
                        __CLASS__ . '.CodeDescription',
149
                        'Required, must be unique. Product identifier used by FoxyCart in transactions. All leading and trailing spaces are removed on save.'
150
                    )),
151
                DropdownField::create('FoxyCategoryID')
152
                    ->setTitle($this->owner->fieldLabel('FoxyCategoryID'))
0 ignored issues
show
Bug introduced by
The method fieldLabel() does not exist on Dynamic\Foxy\Extension\Purchasable. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

152
                    ->setTitle($this->owner->/** @scrutinizer ignore-call */ fieldLabel('FoxyCategoryID'))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
153
                    ->setSource(FoxyCategory::get()->map())
154
                    ->setDescription(_t(
155
                        __CLASS__ . '.FoxyCategoryDescription',
156
                        'Required. Must also exist in
157
                        <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories"
158
                            target="_blank">
159
                            Foxy Categories
160
                        </a>.
161
                        Used to set category specific options like shipping and taxes. Managed in Foxy > Categories'
162
                    ))
163
                    ->setEmptyString(''),
164
                TextField::create('ReceiptTitle')
165
                    ->setDescription(_t(
166
                        __CLASS__ . '.ReceiptTitleDescription',
167
                        'Optional. Alternate title to display on order receipt'
168
                    )),
169
            ],
170
            'Content'
171
        );
172
173
        if ($this->owner->exists()) {
0 ignored issues
show
Bug introduced by
The method exists() does not exist on Dynamic\Foxy\Extension\Purchasable. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

173
        if ($this->owner->/** @scrutinizer ignore-call */ exists()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
174
            $variationsConfig = GridFieldConfig_RelationEditor::create()
175
                ->removeComponentsByType([
176
                    GridFieldAddExistingAutocompleter::class,
177
                    GridFieldPaginator::class,
178
                    GridFieldPageCount::class,
179
                    GridFieldSortableHeader::class,
180
                ])
181
                ->addComponents([
182
                    new GridFieldOrderableRows('SortOrder'),
183
                    new GridFieldTitleHeader(),
184
                    new GridFieldGroupable(
185
                        'VariationTypeID',    // The fieldname to set the Group
186
                        'Variation Type',   // A description of the function of the group
187
                        'none',         // A title/header for items without a group/unassigned
188
                        VariationType::get()->sort('SortOrder')->map()->toArray()
189
                    )
190
                ]);
191
192
            $fields->addFieldToTab(
193
                'Root.Variations',
194
                GridField::create(
195
                    'Variations',
196
                    'Variations',
197
                    $this->owner->Variations(),
198
                    $variationsConfig
199
                )
200
            );
201
        }
202
203
        $fields->addFieldsToTab(
204
            'Root.Inventory',
205
            [
206
                NumericField::create('QuantityMax')
207
                    ->setTitle('Maximum quantity allowed in the cart')
208
                    ->setDescription('For unlimited enter 0')
209
                    ->addExtraClass('stacked'),
210
                CheckboxField::create('Available')
211
                    ->setDescription(_t(
212
                        __CLASS__ . '.AvailableDescription',
213
                        'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"'
214
                    )),
215
            ]
216
        );
217
    }
218
219
    /**
220
     * @return RequiredFields
221
     */
222
    public function getCMSValidator()
223
    {
224
        return new RequiredFields([
225
            "Price",
226
            "Code",
227
            "FoxyCategoryID",
228
        ]);
229
    }
230
231
    /**
232
     * @return bool
233
     */
234
    public function getIsAvailable()
235
    {
236
        if (!$this->owner->Available) {
237
            return false;
238
        }
239
240
        if (!$this->owner->Variations()->count()) {
241
            return true;
242
        }
243
244
        foreach ($this->owner->Variations() as $variation) {
245
            if ($variation->Available) {
246
                return true;
247
            }
248
        }
249
    }
250
251
    /**
252
     * @return mixed
253
     */
254
    public function isAvailable()
255
    {
256
        Deprecation::notice('1.4', 'Use getIsAvailable() instead');
257
        return $this->getIsAvailable();
258
    }
259
260
    /**
261
     * @return bool
262
     */
263
    public function isProduct()
264
    {
265
        return true;
266
    }
267
268
    /**
269
     * @return array
270
     */
271
    public function providePermissions()
272
    {
273
        return [
274
            'MANAGE_FOXY_PRODUCTS' => [
275
                'name' => _t(
276
                    __CLASS__ . '.PERMISSION_MANAGE_PRODUCTS_DESCRIPTION',
277
                    'Manage products'
278
                ),
279
                'category' => _t(
280
                    __CLASS__ . '.PERMISSIONS_CATEGORY',
281
                    'Foxy'
282
                ),
283
                'help' => _t(
284
                    __CLASS__ . '.PERMISSION_MANAGE_PRODUCTS_HELP',
285
                    'Manage products and related settings'
286
                ),
287
                'sort' => 400,
288
            ],
289
        ];
290
    }
291
292
    /**
293
     * @param $member
294
     * @return bool|int|void
295
     */
296
    public function canCreate($member)
297
    {
298
        if (!$member) {
299
            $member = Security::getCurrentUser();
300
        }
301
302
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
303
    }
304
305
    /**
306
     * @param $member
307
     * @return bool|int|void|null
308
     */
309
    public function canEdit($member)
310
    {
311
        if (!$member) {
312
            $member = Security::getCurrentUser();
313
        }
314
315
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
316
    }
317
318
    /**
319
     * @param $member
320
     * @return bool|int|void
321
     */
322
    public function canDelete($member)
323
    {
324
        if (!$member) {
325
            $member = Security::getCurrentUser();
326
        }
327
328
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
329
    }
330
331
    /**
332
     * @param null $member
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $member is correct as it would always require null to be passed?
Loading history...
333
     * @return bool|int
334
     */
335
    public function canUnpublish($member = null)
336
    {
337
        if (!$member) {
0 ignored issues
show
introduced by
$member is of type null, thus it always evaluated to false.
Loading history...
338
            $member = Security::getCurrentUser();
339
        }
340
341
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
342
    }
343
344
    /**
345
     * @param $member
346
     * @return bool|int
347
     */
348
    public function canArchive($member = null)
349
    {
350
        if (!$member) {
351
            $member = Security::getCurrentUser();
352
        }
353
354
        return Permission::checkMember($member, 'MANAGE_FOXY_PRODUCTS');
355
    }
356
357
    /**
358
     *
359
     */
360
    public function onBeforeWrite()
361
    {
362
        // trim spaces and replace duplicate spaces
363
        $trimmed = trim($this->owner->Code);
364
        $this->owner->Code = preg_replace('/\s+/', ' ', $trimmed);
365
    }
366
}
367