1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
use Dynamic\FoxyStripe\Model\FoxyStripeClient; |
4
|
|
|
|
5
|
|
|
class FoxyStripeSiteConfig extends DataExtension{ |
6
|
|
|
|
7
|
|
|
private static $db = array( |
8
|
|
|
'StoreTitle' => 'Varchar(255)', |
9
|
|
|
'StoreName' => 'Varchar(255)', |
10
|
|
|
'StoreURL' => 'Varchar(255)', |
11
|
|
|
'ReceiptURL' => 'Varchar(255)', |
12
|
|
|
'StoreEmail' => 'Varchar(255)', |
13
|
|
|
'FromEmail' => 'Varchar(255)', |
14
|
|
|
'StorePostalCode' => 'Varchar(10)', |
15
|
|
|
'StoreCountry' => 'Varchar(100)', |
16
|
|
|
'StoreRegion' => 'Varchar(100)', |
17
|
|
|
'StoreLocaleCode' => 'Varchar(10)', |
18
|
|
|
'StoreLogoURL' => 'Varchar(255)', |
19
|
|
|
'CheckoutType' => 'Varchar(50)', |
20
|
|
|
'BccEmail' => 'Boolean', |
21
|
|
|
'UseWebhook' => 'Boolean', |
22
|
|
|
'StoreKey' => 'Varchar(60)', |
23
|
|
|
'CartValidation' => 'Boolean', |
24
|
|
|
'UseSingleSignOn' => 'Boolean', |
25
|
|
|
'AllowMultiship' => 'Boolean', |
26
|
|
|
'StoreTimezone' => 'Varchar(100)', |
27
|
|
|
'MultiGroup' => 'Boolean', |
28
|
|
|
'ProductLimit' => 'Int', |
29
|
|
|
'MaxQuantity' => 'Int', |
30
|
|
|
'client_id' => 'Varchar(255)', |
31
|
|
|
'client_secret' => 'Varchar(255)', |
32
|
|
|
'access_token' => 'Varchar(255)', |
33
|
|
|
'refresh_token' => 'Varchar(255)', |
34
|
|
|
); |
35
|
|
|
|
36
|
|
|
// Set Default values |
37
|
|
|
private static $defaults = array( |
38
|
|
|
'ProductLimit' => 10 |
39
|
|
|
); |
40
|
|
|
|
41
|
1 |
|
public function updateCMSFields(FieldList $fields){ |
42
|
|
|
|
43
|
|
|
// set TabSet names to avoid spaces from camel case |
44
|
1 |
|
$fields->addFieldToTab('Root', new TabSet('FoxyStripe', 'FoxyStripe')); |
45
|
|
|
|
46
|
|
|
// settings tab |
47
|
1 |
|
$fields->addFieldsToTab('Root.FoxyStripe.Settings', array( |
48
|
|
|
// Store Details |
49
|
1 |
|
HeaderField::create('StoreDetails', _t('FoxyStripeSiteConfig.StoreDetails', 'Store Settings'), 3), |
50
|
1 |
|
LiteralField::create('DetailsIntro', _t( |
51
|
1 |
|
'FoxyStripeSiteConfig.DetailsIntro', |
52
|
|
|
'<p>Maps to data in your <a href="https://admin.foxycart.com/admin.php?ThisAction=EditStore" target="_blank">FoxyCart store settings</a>.' |
53
|
1 |
|
)), |
54
|
1 |
|
TextField::create('StoreTitle') |
55
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.StoreTitle', 'Store Name')) |
56
|
1 |
|
->setDescription(_t('FoxyStripeSiteConfig.StoreTitleDescription', 'The name of your store as you\'d like it displayed to your customers')), |
57
|
1 |
|
TextField::create('StoreName') |
58
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.StoreName', 'Store Domain')) |
59
|
1 |
|
->setDescription(_t('FoxyStripeSiteConfig.StoreNameDescription', 'This is a unique FoxyCart subdomain for your cart, checkout, and receipt')), |
60
|
1 |
|
TextField::create('StoreURL') |
61
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.StoreURL', 'Store URL')) |
62
|
1 |
|
->setDescription(_t('FoxyStripeSiteConfig.StoreURLDescription', 'The URL of your online store')), |
63
|
1 |
|
TextField::create('ReceiptURL') |
64
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.ReceiptURL', 'Receipt URL')) |
65
|
1 |
|
->setDescription(_t('FoxyStripeSiteConfig.ReceiptURLDescription', 'By default, FoxyCart sends customers back to the page referrer after completing a purchase. Instead, you can set a specific URL here')), |
66
|
1 |
|
TextField::create('StoreEmail') |
67
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.StoreEmail', 'Store Email')) |
68
|
1 |
|
->setDescription(_t('FoxyStripeSiteConfig.StoreEmailDescription', 'This is the email address of your store. By default, this will be the from address for your store receipts. ')), |
69
|
1 |
|
TextField::create('FromEmail') |
70
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.FromEmail', 'From Email')) |
71
|
1 |
|
->setDescription(_t('FoxyStripeSiteConfig.FromEmailDescription', 'Used for when you want to specify a different from email than your store\'s email address')), |
72
|
1 |
|
TextField::create('StorePostalCode', 'Postal Code'), |
73
|
1 |
|
CountryDropdownField::create('StoreCountry', 'Country'), |
74
|
1 |
|
TextField::create('StoreRegion', 'State/Region'), |
75
|
1 |
|
TextField::create('StoreLocaleCode', 'Locale Code') |
76
|
1 |
|
->setDescription('example: en_US'), |
77
|
1 |
|
TextField::create('StoreTimezone', 'Store timezone'), |
78
|
1 |
|
TextField::create('StoreLogoURL', 'Logo URL') |
79
|
1 |
|
->setAttribute('placeholder', 'http://') |
80
|
|
|
|
81
|
|
|
// Advanced Settings |
82
|
|
|
/* |
|
|
|
|
83
|
|
|
HeaderField::create('AdvanceHeader', _t('FoxyStripeSiteConfig.AdvancedHeader', 'Advanced Settings'), 3), |
84
|
|
|
LiteralField::create('AdvancedIntro', _t( |
85
|
|
|
'FoxyStripeSiteConfig.AdvancedIntro', |
86
|
|
|
'<p>Maps to data in your <a href="https://admin.foxycart.com/admin.php?ThisAction=EditAdvancedFeatures" target="_blank">FoxyCart advanced store settings</a>.</p>' |
87
|
|
|
)), |
88
|
|
|
ReadonlyField::create('DataFeedLink', _t('FoxyStripeSiteConfig.DataFeedLink', 'FoxyCart DataFeed URL'), self::getDataFeedLink()) |
89
|
|
|
->setDescription(_t('FoxyStripeSiteConfig.DataFeedLinkDescription', 'copy/paste to FoxyCart')), |
90
|
|
|
CheckboxField::create('CartValidation') |
91
|
|
|
->setTitle(_t('FoxyStripeSiteConfig.CartValidation', 'Enable Cart Validation')) |
92
|
|
|
->setDescription(_t( |
93
|
|
|
'FoxyStripeSiteConfig.CartValidationDescription', |
94
|
|
|
'You must <a href="https://admin.foxycart.com/admin.php?ThisAction=EditAdvancedFeatures#use_cart_validation" target="_blank">enable cart validation</a> in the FoxyCart admin.' |
95
|
|
|
)), |
96
|
|
|
ReadonlyField::create('StoreKey') |
97
|
|
|
->setTitle(_t('FoxyStripeSiteConfig.StoreKey', 'FoxyCart API Key')) |
98
|
|
|
->setDescription(_t('FoxyStripeSiteConfig.StoreKeyDescription', 'copy/paste to FoxyCart')), |
99
|
|
|
ReadonlyField::create('SSOLink', _t('FoxyStripeSiteConfig.SSOLink', 'Single Sign On URL'), self::getSSOLink()) |
100
|
|
|
->setDescription(_t('FoxyStripeSiteConfig.SSOLinkDescription', 'copy/paste to FoxyCart')) |
101
|
|
|
*/ |
102
|
1 |
|
)); |
103
|
|
|
|
104
|
1 |
|
$fields->addFieldsToTab('Root.FoxyStripe.Advanced', [ |
105
|
1 |
|
HeaderField::create('AdvanceHeader', _t('FoxyStripeSiteConfig.AdvancedHeader', 'Advanced Settings'), 3), |
106
|
1 |
|
LiteralField::create('AdvancedIntro', _t( |
107
|
1 |
|
'FoxyStripeSiteConfig.AdvancedIntro', |
108
|
|
|
'<p>Maps to data in your <a href="https://admin.foxycart.com/admin.php?ThisAction=EditAdvancedFeatures" target="_blank">FoxyCart advanced store settings</a>.</p>' |
109
|
1 |
|
)), |
110
|
1 |
|
DropdownField::create('CheckoutType', 'Checkout Type', $this->getCheckoutTypes()), |
111
|
1 |
|
CheckboxField::create('BccEmail', 'BCC Admin Email') |
112
|
1 |
|
->setDescription('bcc all receipts to store\'s email address'), |
113
|
1 |
|
CheckboxField::create('UseWebhook', 'Use Webhook') |
114
|
1 |
|
->setDescription('record order history in CMS, allows customers to view their order history'), |
115
|
1 |
|
ReadonlyField::create('WebhookURL', 'Webhook URL', self::getDataFeedLink()), |
116
|
1 |
|
ReadonlyField::create('StoreKey', 'Webhook Key', self::getDataFeedLink()), |
117
|
1 |
|
CheckboxField::create('CartValidation', 'Use cart validation'), |
118
|
1 |
|
CheckboxField::create('UseSingleSignOn', 'Use single sign on') |
119
|
1 |
|
->setDescription('Sync user accounts between FoxyCart and your website'), |
120
|
1 |
|
ReadonlyField::create('SingleSignOnURL', 'Single sign on URL', self::getSSOLink()), |
121
|
1 |
|
CheckboxField::create('AllowMultiship', 'Allow multiple shipments per order') |
122
|
1 |
|
]); |
123
|
|
|
|
124
|
|
|
// configuration warning |
125
|
1 |
View Code Duplication |
if(FoxyCart::store_name_warning()!==null){ |
|
|
|
|
126
|
1 |
|
$fields->insertBefore(LiteralField::create( |
127
|
1 |
|
"StoreSubDomainHeaderWarning", |
128
|
1 |
|
_t( |
129
|
1 |
|
'FoxyStripeSiteConfig.StoreSubDomainHeadingWarning', |
130
|
|
|
"<p class=\"message error\">Store sub-domain must be entered in the <a href=\"/admin/settings/\">site settings</a></p>" |
131
|
1 |
|
) |
132
|
1 |
|
), 'StoreDetails'); |
|
|
|
|
133
|
1 |
|
} |
134
|
|
|
|
135
|
|
|
// products tab |
136
|
1 |
|
$fields->addFieldsToTab('Root.FoxyStripe.Products', array( |
137
|
1 |
|
HeaderField::create('ProductHeader', _t('FoxyStripeSiteConfig.ProductHeader', 'Products'), 3), |
138
|
1 |
|
CheckboxField::create('MultiGroup') |
139
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.MultiGroup', 'Multiple Groups')) |
140
|
1 |
|
->setDescription(_t( |
141
|
1 |
|
'FoxyStripeSiteConfig.MultiGroupDescription', |
142
|
|
|
'Allows products to be shown in multiple Product Groups' |
143
|
1 |
|
)), |
144
|
1 |
|
HeaderField::create('ProductGroupHD', _t('FoxyStripeSiteConfig.ProductGroupHD', 'Product Groups'), 3), |
145
|
1 |
|
NumericField::create('ProductLimit') |
146
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.ProductLimit', 'Products per Page')) |
147
|
1 |
|
->setDescription(_t( |
148
|
1 |
|
'FoxyStripeSiteConfig.ProductLimitDescription', |
149
|
|
|
'Number of Products to show per page on a Product Group' |
150
|
1 |
|
)), |
151
|
1 |
|
HeaderField::create('ProductQuantityHD', _t('FoxyStripeSiteConfig.ProductQuantityHD', 'Product Form Max Quantity'), 3), |
152
|
1 |
|
NumericField::create('MaxQuantity') |
153
|
1 |
|
->setTitle(_t('FoxyStripeSiteConfig.MaxQuantity', 'Max Quantity')) |
154
|
1 |
|
->setDescription(_t( |
155
|
1 |
|
'FoxyStripeSiteConfig.MaxQuantityDescription', |
156
|
|
|
'Sets max quantity for product form dropdown (add to cart form - default 10)' |
157
|
1 |
|
)) |
158
|
1 |
|
)); |
159
|
|
|
|
160
|
|
|
// categories tab |
161
|
1 |
|
$fields->addFieldsToTab('Root.FoxyStripe.Categories', array( |
162
|
1 |
|
HeaderField::create('CategoryHD', _t('FoxyStripeSiteConfig.CategoryHD', 'FoxyStripe Categories'), 3), |
163
|
1 |
|
LiteralField::create('CategoryDescrip', _t( |
164
|
1 |
|
'FoxyStripeSiteConfig.CategoryDescrip', |
165
|
|
|
'<p>FoxyCart Categories offer a way to give products additional behaviors that cannot be accomplished by product options alone, including category specific coupon codes, shipping and handling fees, and email receipts. <a href="https://wiki.foxycart.com/v/2.0/categories" target="_blank">Learn More</a></p><p>Categories you\'ve created in FoxyStripe must also be created in your <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories" target="_blank">FoxyCart Categories</a> admin panel.</p>' |
166
|
1 |
|
)), |
167
|
1 |
|
GridField::create( |
168
|
1 |
|
'ProductCategory', |
169
|
1 |
|
_t('FoxyStripeSiteConfig.ProductCategory', 'FoxyCart Categories'), |
170
|
1 |
|
ProductCategory::get(), |
171
|
1 |
|
GridFieldConfig_RecordEditor::create() |
172
|
1 |
|
) |
173
|
1 |
|
)); |
174
|
|
|
|
175
|
|
|
// option groups tab |
176
|
1 |
|
$fields->addFieldsToTab('Root.FoxyStripe.Groups', array( |
177
|
1 |
|
HeaderField::create('OptionGroupsHead', _t('FoxyStripeSiteConfig', 'Product Option Groups'), 3), |
178
|
1 |
|
LiteralField::create('OptionGroupsDescrip', _t( |
179
|
1 |
|
'FoxyStripeSiteConfig.OptionGroupsDescrip', |
180
|
|
|
'<p>Product Option Groups allow you to name a set of product options.</p>' |
181
|
1 |
|
)), |
182
|
1 |
|
GridField::create( |
183
|
1 |
|
'OptionGroup', |
184
|
1 |
|
_t('FoxyStripeSiteConfig.OptionGroup', 'Product Option Groups'), |
185
|
1 |
|
OptionGroup::get(), |
186
|
1 |
|
GridFieldConfig_RecordEditor::create() |
187
|
1 |
|
) |
188
|
1 |
|
)); |
189
|
|
|
|
190
|
|
|
// api tab |
191
|
1 |
|
$fields->addFieldsToTab('Root.FoxyStripe.API', [ |
192
|
1 |
|
HeaderField::create('APIHD', 'FoxyCart API Settings', 3), |
193
|
1 |
|
TextField::create('client_id', 'FoxyCart Client ID'), |
194
|
1 |
|
TextField::create('client_secret', 'FoxyCart Client Secret'), |
195
|
1 |
|
TextField::create('access_token', 'FoxyCart Access Token'), |
196
|
1 |
|
TextField::create('refresh_token', 'FoxyCart Refresh Token'), |
197
|
1 |
|
]); |
198
|
|
|
|
199
|
1 |
|
} |
200
|
|
|
|
201
|
2 |
|
private static function getSSOLink() { |
202
|
2 |
|
return Director::absoluteBaseURL()."foxystripe/sso/"; |
203
|
|
|
} |
204
|
|
|
|
205
|
2 |
|
private static function getDataFeedLink() { |
206
|
2 |
|
return Director::absoluteBaseURL()."foxystripe/"; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
// generate key on install |
210
|
3 |
|
public function requireDefaultRecords() { |
211
|
|
|
|
212
|
3 |
|
parent::requireDefaultRecords(); |
213
|
|
|
|
214
|
3 |
|
$siteConfig = SiteConfig::current_site_config(); |
215
|
|
|
|
216
|
3 |
|
if(!$siteConfig->StoreKey) { |
217
|
3 |
|
$key = FoxyCart::setStoreKey(); |
218
|
3 |
|
while(!ctype_alnum($key)){ |
219
|
|
|
$key = FoxyCart::setStoreKey(); |
220
|
|
|
} |
221
|
3 |
|
$siteConfig->StoreKey = $key; |
222
|
3 |
|
$siteConfig->write(); |
223
|
3 |
|
DB::alteration_message($siteConfig->ClassName.": created FoxyCart Store Key " . $key, 'created'); |
224
|
3 |
|
} |
225
|
3 |
|
} |
226
|
|
|
|
227
|
1 |
|
public function getCheckoutTypes() |
228
|
|
|
{ |
229
|
|
|
return [ |
230
|
1 |
|
"default_account" => "Allow guest and customer accounts, default to account", |
231
|
1 |
|
"default_guest" => "Allow guest and customer accounts, default to guest", |
232
|
1 |
|
"account_only" => "Allow customer accounts only", |
233
|
1 |
|
"guest_only" => "Allow guests only", |
234
|
1 |
|
]; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* @return array |
239
|
|
|
*/ |
240
|
1 |
|
public function getDataMap() |
241
|
|
|
{ |
242
|
|
|
return [ |
243
|
1 |
|
'store_name' => $this->owner->StoreTitle, |
244
|
1 |
|
'store_domain' => $this->owner->StoreName, |
245
|
1 |
|
'store_url' => $this->owner->StoreURL, |
246
|
1 |
|
'receipt_continue_url' => $this->owner->ReceiptURL, |
247
|
1 |
|
'store_email' => $this->owner->StoreEmail, |
248
|
1 |
|
'from_email' => $this->owner->FromEmail, |
249
|
1 |
|
'postal_code' => $this->owner->StorePostalCode, |
250
|
1 |
|
'country' => $this->owner->StoreCountry, |
251
|
1 |
|
'region' => $this->owner->StoreRegion, |
252
|
1 |
|
'locale_code' => $this->owner->StoreLocaleCode, |
253
|
1 |
|
'logo_url' => $this->owner->StoreLogoURL, |
254
|
1 |
|
'checkout_type' => $this->owner->CheckoutType, |
255
|
1 |
|
'bcc_on_receipt_email' => $this->owner->BccEmail, |
256
|
1 |
|
'use_webhook' => $this->owner->UseWebhook, |
257
|
1 |
|
'webhook_url' => $this->getDataFeedLink(), |
258
|
1 |
|
'webhook_key' => $this->owner->StoreKey, |
259
|
1 |
|
'use_cart_validation' => $this->owner->CartValidation, |
260
|
1 |
|
'use_single_sign_on' => $this->owner->UseSingleSignOn, |
261
|
1 |
|
'single_sign_on_url' => $this->getSSOLink(), |
262
|
1 |
|
'customer_password_hash_type' => 'sha1_salted_suffix', |
263
|
1 |
|
'customer_password_hash_config' => 40, |
264
|
1 |
|
'features_multiship' => $this->owner->AllowMultiship, |
265
|
1 |
|
'timezone' => $this->StoreTimezone, |
|
|
|
|
266
|
1 |
|
]; |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* if StoreTitle is empty, grab values from FoxyCart |
271
|
|
|
* |
272
|
|
|
* example of 2 way sync for future reference |
273
|
|
|
*/ |
274
|
48 |
|
public function onBeforeWrite() |
275
|
|
|
{ |
276
|
48 |
|
parent::onBeforeWrite(); |
277
|
|
|
|
278
|
48 |
|
if ($this->owner->ID && !$this->owner->StoreTitle && $this->owner->access_token) { |
279
|
|
|
if ($fc = new FoxyStripeClient()) { |
280
|
|
|
$client = $fc->getClient(); |
281
|
|
|
$errors = []; |
282
|
|
|
|
283
|
|
|
$result = $client->get($fc->getCurrentStore()); |
284
|
|
|
$this->owner->StoreTitle = $result['store_name']; |
285
|
|
|
|
286
|
|
|
$errors = array_merge($errors, $client->getErrors($result)); |
287
|
|
|
if (count($errors)) { |
288
|
|
|
\SS_Log::log('FoxyStripeSiteConfig::onBeforeWrite errors - ' . json_encode($errors), \SS_Log::WARN); |
289
|
|
|
} |
290
|
|
|
} |
291
|
|
|
} |
292
|
48 |
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* push updated data to FoxyCart |
296
|
|
|
*/ |
297
|
48 |
|
public function onAfterWrite() |
298
|
|
|
{ |
299
|
48 |
|
parent::onAfterWrite(); |
300
|
|
|
|
301
|
48 |
|
if ($this->owner->isChanged() && $this->owner->access_token) { |
302
|
|
|
if ($fc = new FoxyStripeClient()) { |
303
|
|
|
$fc->updateStore($this->getDataMap()); |
304
|
|
|
} |
305
|
|
|
} |
306
|
48 |
|
} |
307
|
|
|
} |
308
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.