Skip to content

Commit

Permalink
Merge pull request #19 from creative-commoners/pulls/1.0/item-quantity
Browse files Browse the repository at this point in the history
NEW Add validation for "add item" requests, implement maximum item quantity in cart
  • Loading branch information
fspringveldt committed May 25, 2017
2 parents 4c173a8 + 72709d3 commit 29e767a
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Expand Up @@ -10,5 +10,5 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[{*.yml,package.json}]
[{*.yml,package.json,*.scss,*.css,*.js}]
indent_size = 2
43 changes: 41 additions & 2 deletions code/controllers/DMSDocumentCartController.php
Expand Up @@ -70,8 +70,13 @@ public function add(SS_HTTPRequest $request)
{
$quantity = ($request->requestVar('quantity')) ? intval($request->requestVar('quantity')) : 1;
$documentId = (int)$request->param('ID');
$result = true;
$message = '';

if ($doc = DMSDocument::get()->byID($documentId)) {
if ($doc->isAllowedInCart() && $doc->canView()) {
/** @var ValidationResult $validate */
$validate = $this->validateAddRequest($quantity, $doc);
if ($validate->valid()) {
if ($this->getCart()->getItem($documentId)) {
$this->getCart()->updateItemQuantity($documentId, $quantity);
} else {
Expand All @@ -83,13 +88,19 @@ public function add(SS_HTTPRequest $request)
if (isset($backURL) && preg_match('/^\//', $backURL)) {
$this->getCart()->setBackUrl($backURL);
}
} else {
$message = $validate->starredList();
$result = false;
}
}

if ($request->isAjax()) {
$this->response->addHeader('Content-Type', 'application/json');
return Convert::raw2json(array('result' => $result, 'message' => $message));
}

return Convert::raw2json(array('result' => true));
if (!$result) {
Session::set('dms-cart-validation-message', $message);
}

if ($backURL = $request->getVar('BackURL')) {
Expand Down Expand Up @@ -153,4 +164,32 @@ public function getCart()
{
return singleton('DMSDocumentCart');
}

/**
* Validates a request to add a document to the cart
*
* @param int $quantity
* @param DMSDocument $document
* @return ValidationResult
*/
protected function validateAddRequest($quantity, DMSDocument $document)
{
$result = ValidationResult::create();

if (!$document->isAllowedInCart()) {
$result->error(_t(__CLASS__ . '.ERROR_NOT_ALLOWED', 'You are not allowed to add this document'));
}

if ($document->getHasQuantityLimit() && $quantity > $document->getMaximumQuantity()) {
$result->error(_t(
__CLASS__ . '.ERROR_QUANTITY_EXCEEDED',
'You can\'t add {quantity} of this document',
array('quantity' => $quantity)
));
}

$this->extend('updateValidateAddRequest', $result, $quantity, $document);

return $result;
}
}
59 changes: 54 additions & 5 deletions code/extensions/DMSDocumentCartExtension.php
Expand Up @@ -16,9 +16,10 @@ class DMSDocumentCartExtension extends DataExtension
private $cartController;

private static $db = array(
'AllowedInCart' => 'Boolean',
'AllowedInCart' => 'Boolean',
'MaximumCartQuantity' => 'Int',
// Running total of print requests on this document
'PrintRequestCount' => 'Int',
'PrintRequestCount' => 'Int',
);

/**
Expand All @@ -33,13 +34,27 @@ public function isAllowedInCart()

public function updateCMSFields(FieldList $fields)
{
$fields->insertBefore(
'Description',
Requirements::javascript(DMS_CART_DIR . '/javascript/dmscart.js');

$newFields = array(
CheckboxField::create(
'AllowedInCart',
_t('DMSDocumentCart.ALLOWED_IN_CART', 'Allowed in document cart')
)
)->addExtraClass('dms-allowed-in-cart'),
TextField::create(
'MaximumCartQuantity',
_t('DMSDocumentCart.MAXIMUM_CART_QUANTITY', 'Maximum cart quantity')
)->setRightTitle(
_t(
'DMSDocumentCart.MAXIMUM_CART_QUANTITY_HELP',
'If set, this will enforce a maximum number of this item that can be ordered per cart'
)
)->addExtraClass('dms-maximum-cart-quantity hide')
);

foreach ($newFields as $field) {
$fields->insertBefore($field, 'Description');
}
}

/**
Expand All @@ -65,6 +80,26 @@ public function isInCart()
return (bool) $this->getCart()->isInCart($this->owner->ID);
}

/**
* Returns whether the current document has a limit on how many items can be added to a single cart
*
* @return bool
*/
public function getHasQuantityLimit()
{
return $this->owner->getMaximumQuantity() > 0;
}

/**
* Get the maximum quantity of this document that can be ordered in a single cart
*
* @return int
*/
public function getMaximumQuantity()
{
return (int) $this->owner->MaximumCartQuantity;
}

/**
* Builds and returns a valid DMSDocumentController URL from the given $action link
*
Expand Down Expand Up @@ -114,4 +149,18 @@ public function getCart()
{
return $this->getCartController()->getCart();
}

/**
* Returns any validation messages that may have been in the session and clears them
*
* @return false
*/
public function getValidationResult()
{
if ($result = Session::get('dms-cart-validation-message')) {
Session::clear('dms-cart-validation-message');
return $result;
}
return false;
}
}
9 changes: 2 additions & 7 deletions css/dms-cart.css
@@ -1,8 +1,3 @@
.dms-cart-actions .hidden {
display: none;
visibility: hidden;
.dms-cart-actions .dms-cart-actions-viewcartlink:before {
content: "• "
}

.dms-cart-actions .dms-bullet-item:before {
content: "• "
}
30 changes: 30 additions & 0 deletions javascript/dmscart.js
@@ -0,0 +1,30 @@
(function ($) {
"use strict";

$.entwine('ss', function ($) {
$('input.dms-allowed-in-cart').entwine({
/**
* Toggle the "maximum cart quantity" field visibility depending on whether "allowed in document cart" is checked
*/
onclick: function (e) {
jQuery('.field.dms-maximum-cart-quantity').toggle();
this.getElements().removeClass('hide');
},
/**
* Initially show the "maximum cart quantity" field visibility if the "allowed in document cart" checkbox
* is checked
*/
onmatch: function(e) {
if (this.is(':checked')) {
this.getElements().removeClass('hide');
}
},
/**
* Returns all DOM elements with the field's class applied
*/
getElements: function() {
return jQuery('.dms-maximum-cart-quantity');
}
});
});
}(jQuery));
8 changes: 8 additions & 0 deletions lang/en.yml
@@ -0,0 +1,8 @@
en:
DMSDocumentCart:
ALLOWED_IN_CART: Allowed in document cart
MAXIMUM_CART_QUANTITY: Maximum cart quantity
MAXIMUM_CART_QUANTITY_HELP: If set, this will enforce a maximum number of this item that can be ordered per cart
DMSDocumentCartController:
ERROR_NOT_ALLOWED: You are not allowed to add this document
ERROR_QUANTITY_EXCEEDED: You can't add {quantity} of this document
18 changes: 13 additions & 5 deletions templates/includes/CartActions.ss
@@ -1,15 +1,23 @@
<% if $isAllowedInCart %>
<% require css('dms-cart/css/dms-cart.css') %>
<div class="dms-cart-actions">
<% if $getValidationResult %>
<form>
<p class="message dms-cart-actions-messages bad">$getValidationResult</p>
</form>
<% end_if %>
<p>
<a class="<% if not $isInCart %>hidden<% end_if %>"
href="$getActionLink('remove')"><%t DMSCart.REMOVE_FROM_CART "Remove from cart" %> </a>
<a class="<% if $isInCart %>hidden<% end_if %>"
href="$getActionLink('add')"><%t DMSCart.ADD_TO_CART "Request a printed copy" %> </a>
<% if $isInCart %>
<a class="dms-bullet-item <% if not $isInCart %>hidden<% end_if %>" href="$getActionLink('checkout')"
<a class="dms-cart-actions-removelink" href="$getActionLink('remove')">
<%t DMSCart.REMOVE_FROM_CART "Remove from cart" %>
</a>
<a class="dms-cart-actions-viewcartlink" href="$getActionLink('checkout')"
title="<%t DMSCart.VIEW_MY_CART "View my Document cart" %>"
><%t DMSCart.VIEW_MY_CART "View my Document cart" %></a>
<% else %>
<a class="dms-cart-actions-addlink" href="$getActionLink('add')">
<%t DMSCart.ADD_TO_CART "Request a printed copy" %>
</a>
<% end_if %>
</p>
</div>
Expand Down
21 changes: 21 additions & 0 deletions tests/DMSDocumentCartControllerTest.php
Expand Up @@ -158,4 +158,25 @@ public function testCart()
//For good measure assert it's empty
$this->assertTrue($this->controller->getIsCartEmpty());
}

/**
* Ensure that a validation error is shown when requesting to add more of a document that is allowed
*/
public function testCannotAddMoreThanSuggestedQuantityOfItem()
{
$document = $this->objFromFixture('DMSDocument', 'limited_supply');
$result = $this->get('/documentcart/add/' . $document->ID . '?quantity=5&ajax=1');
$this->assertContains('You can\'t add 5 of this document', (string) $result->getBody());
}

/**
* Ensure that when a document that cannot be added to the cart is added to the cart, a validation error is
* returned
*/
public function testValidationErrorReturnedOnInvalidAdd()
{
$document = $this->objFromFixture('DMSDocument', 'not_allowed_in_cart');
$result = $this->get('/documentcart/add/' . $document->ID . '?ajax=1');
$this->assertContains('You are not allowed to add this document', (string) $result->getBody());
}
}
11 changes: 10 additions & 1 deletion tests/DMSDocumentCartTest.yml
Expand Up @@ -11,7 +11,16 @@ DMSDocument:
doc2:
Filename: Doc2
Title: Doc2
limited_supply:
Filename: Doc3
Title: Doc3
AllowedInCart: 1
MaximumCartQuantity: 3
not_allowed_in_cart:
Filename: Doc4
Title: Doc4
AllowedInCart: 0
DMSDocumentCartCheckoutPage:
page1:
ThanksMessage: Thank you for your submission
CartEmailRecipient: =>Member.joe
CartEmailRecipient: =>Member.joe
51 changes: 51 additions & 0 deletions tests/extensions/DMSDocumentCartExtensionTest.php
@@ -0,0 +1,51 @@
<?php

class DMSDocumentCartExtensionTest extends SapphireTest
{
protected $requiredExtensions = array(
'DMSDocument' => array('DMSDocumentCartExtension')
);

public function testMaximumCartQuantity()
{
$document = DMSDocument::create(array('AllowedInCart' => true, 'MaximumCartQuantity' => ''));

$this->assertFalse($document->getHasQuantityLimit());

$document->MaximumCartQuantity = 0;
$this->assertFalse($document->getHasQuantityLimit());

$document->MaximumCartQuantity = 1;
$this->assertTrue($document->getHasQuantityLimit());
$this->assertSame(1, $document->getMaximumQuantity());

$document->MaximumCartQuantity = 10;
$this->assertSame(10, $document->getMaximumQuantity());
}

/**
* The CSS classes are required for the CMS Javascript to work, assert that they are correct
*/
public function testCmsFieldsHaveRequiredCssClasses()
{
$fields = DMSDocument::create()->getCMSFields();

$allowedInCart = $fields->fieldByName('AllowedInCart');
$this->assertInstanceOf('CheckboxField', $allowedInCart);
$this->assertTrue((bool) $allowedInCart->hasClass('dms-allowed-in-cart'));

$allowedInCart = $fields->fieldByName('MaximumCartQuantity');
$this->assertInstanceOf('TextField', $allowedInCart);
$this->assertTrue((bool) $allowedInCart->hasClass('dms-maximum-cart-quantity'));
}

/**
* Ensure that validation messages can be retrieved once, cleared, then not again
*/
public function testGetValidationResult()
{
Session::set('dms-cart-validation-message', 'testing');
$this->assertSame('testing', DMSDocument::create()->getValidationResult());
$this->assertFalse(DMSDocument::create()->getValidationResult());
}
}

0 comments on commit 29e767a

Please sign in to comment.