Skip to content

Commit

Permalink
#29 basic admin section for creating/deleting/list the promo code
Browse files Browse the repository at this point in the history
  • Loading branch information
syjer committed Jan 10, 2015
1 parent 23aef63 commit 6ab7f4c
Show file tree
Hide file tree
Showing 12 changed files with 362 additions and 11 deletions.
78 changes: 78 additions & 0 deletions src/main/java/alfio/controller/api/PromoCodeApiController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* This file is part of alf.io.
*
* alf.io is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* alf.io is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with alf.io. If not, see <http://www.gnu.org/licenses/>.
*/
package alfio.controller.api;

import static org.springframework.web.bind.annotation.RequestMethod.*;

import java.time.ZoneId;
import java.util.List;
import java.util.TimeZone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import alfio.manager.EventManager;
import alfio.model.Event;
import alfio.model.PromoCode;
import alfio.model.modification.PromoCodeModification;
import alfio.model.modification.PromoCodeWithFormattedTime;
import alfio.repository.EventRepository;
import alfio.repository.PromoCodeRepository;

@RestController
@RequestMapping("/admin/api")
public class PromoCodeApiController {

private final EventRepository eventRepository;
private final PromoCodeRepository promoCodeRepository;
private final EventManager eventManager;

@Autowired
public PromoCodeApiController(EventRepository eventRepository, PromoCodeRepository promoCodeRepository, EventManager eventManager) {
this.eventRepository = eventRepository;
this.promoCodeRepository = promoCodeRepository;
this.eventManager = eventManager;
}

@RequestMapping(value = "/events/{eventId}/promo-code", method = POST)
public void addPromoCode(@PathVariable("eventId") int eventId, @RequestBody PromoCodeModification promoCode) {
Event event = eventRepository.findById(eventId);
ZoneId zoneId = TimeZone.getTimeZone(event.getTimeZone()).toZoneId();

eventManager.addPromoCode(promoCode.getPromoCode(), eventId, promoCode.getStart().toZonedDateTime(zoneId),
promoCode.getEnd().toZonedDateTime(zoneId), promoCode.getDiscountAmount(), promoCode.getDiscountType());
}

@RequestMapping(value = "/events/{eventId}/promo-code", method = GET)
public List<PromoCodeWithFormattedTime> listPromoCodeInEvent(@PathVariable("eventId") int eventId) {
return eventManager.findPromoCodesInEvent(eventId);
}

@RequestMapping(value = "/events/{eventId}/promo-code/{promoCodeName}", method = DELETE)
public void removePromoCode(@PathVariable("eventId") int eventId, @PathVariable("promoCodeName") String promoCodeName) {
PromoCode promoCode = promoCodeRepository.findPromoCodeInEvent(eventId, promoCodeName);
eventManager.deletePromoCode(promoCode.getId());
}

@RequestMapping(value = "/events/{eventId}/promo-code/{promoCodeName}", method = POST)
public void updatePromoCode(@PathVariable("eventId") int eventId, @RequestBody PromoCodeModification promoCode) {
//FIXME complete. Will be used to disable and/or change validity date
}
}
6 changes: 4 additions & 2 deletions src/main/java/alfio/manager/EventManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import alfio.model.PromoCode.DiscountType;
import alfio.model.modification.EventModification;
import alfio.model.modification.EventWithStatistics;
import alfio.model.modification.PromoCodeWithFormattedTime;
import alfio.model.modification.TicketCategoryModification;
import alfio.model.modification.TicketCategoryWithStatistic;
import alfio.model.transaction.PaymentProxy;
Expand Down Expand Up @@ -534,8 +535,9 @@ public void deletePromoCode(int promoCodeId) {
promoCodeRepository.deletePromoCode(promoCodeId);
}

public List<PromoCode> findPromoCodesInEvent(int eventId) {
return promoCodeRepository.findAllInEvent(eventId);
public List<PromoCodeWithFormattedTime> findPromoCodesInEvent(int eventId) {
ZoneId zoneId = eventRepository.findById(eventId).getZoneId();
return promoCodeRepository.findAllInEvent(eventId).stream().map((p) -> new PromoCodeWithFormattedTime(p, zoneId)).collect(toList());
}

@Data
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/alfio/model/PromoCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,23 @@ public enum DiscountType {
private final int id;
private final String promoCode;
private final int eventId;
private final ZonedDateTime start;
private final ZonedDateTime end;
private final ZonedDateTime utcStart;
private final ZonedDateTime utcEnd;
private final int discountAmount;
private final DiscountType discountType;

public PromoCode(@Column("id")int id,
@Column("promo_code") String promoCode,
@Column("event_id_fk") int eventId,
@Column("start") ZonedDateTime start,
@Column("end") ZonedDateTime end,
@Column("valid_from") ZonedDateTime utcStart,
@Column("valid_to") ZonedDateTime utcEnd,
@Column("discount_amount") int discountAmount,
@Column("discount_type") DiscountType discountType) {
this.id = id;
this.promoCode = promoCode;
this.eventId = eventId;
this.start = start;
this.end = end;
this.utcStart = utcStart;
this.utcEnd = utcEnd;
this.discountAmount = discountAmount;
this.discountType = discountType;
}
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/alfio/model/modification/PromoCodeModification.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* This file is part of alf.io.
*
* alf.io is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* alf.io is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with alf.io. If not, see <http://www.gnu.org/licenses/>.
*/
package alfio.model.modification;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.Getter;
import alfio.model.PromoCode.DiscountType;

@Getter
public class PromoCodeModification {

private final String promoCode;
private final DateTimeModification start;
private final DateTimeModification end;
private final int discountAmount;
private final DiscountType discountType;

@JsonCreator
public PromoCodeModification(@JsonProperty("promoCode") String promoCode,
@JsonProperty("start") DateTimeModification start,
@JsonProperty("end") DateTimeModification end,
@JsonProperty("discountAmount") int discountAmount,
@JsonProperty("discountType") DiscountType discountType) {
this.promoCode = promoCode;
this.start = start;
this.end = end;
this.discountAmount = discountAmount;
this.discountType = discountType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* This file is part of alf.io.
*
* alf.io is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* alf.io is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with alf.io. If not, see <http://www.gnu.org/licenses/>.
*/
package alfio.model.modification;

import java.time.ZoneId;
import java.time.ZonedDateTime;

import com.fasterxml.jackson.annotation.JsonIgnore;

import lombok.experimental.Delegate;
import alfio.model.PromoCode;

public class PromoCodeWithFormattedTime {

@JsonIgnore
@Delegate
private final PromoCode promo;

@JsonIgnore
private final ZoneId eventZoneId;

public PromoCodeWithFormattedTime(PromoCode promo, ZoneId eventZoneId) {
this.promo = promo;
this.eventZoneId = eventZoneId;
}

public boolean isExpired() {
return ZonedDateTime.now(eventZoneId).isAfter(getUtcEnd().withZoneSameInstant(eventZoneId));
}

public String getFormattedStart() {
return getUtcStart().withZoneSameInstant(eventZoneId).format(EventWithStatistics.JSON_DATE_FORMATTER);
}

public String getFormattedEnd() {
return getUtcEnd().withZoneSameInstant(eventZoneId).format(EventWithStatistics.JSON_DATE_FORMATTER);
}
}
2 changes: 1 addition & 1 deletion src/main/resources/alfio/db/HSQLDB/V10__TEST_DATA.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
INSERT INTO organization(name, description, email) VALUES ('demo', 'demo organization', '[email protected]');

insert into event(description, short_name, website_url, website_t_c_url, location, latitude, longitude, start_ts, end_ts, regular_price_cts, currency, available_seats, vat_included, vat, allowed_payment_proxies, private_key, org_id, time_zone, image_url)
values('event desc', 'eventname', 'http://localhost:8080', 'http://localhost:8080', 'demo location', '0', '0', '2015-01-10 05:00:00' , '2015-01-11 04:59:00' , 1000, 'CHF', 440, 'true', 8, 'STRIPE', 'alfio-uberall', 0, 'America/New_York', 'http://localhost:8080/resources/images/sample-logo.png');
values('event desc', 'eventname', 'http://localhost:8080', 'http://localhost:8080', 'demo location', '0', '0', '2015-10-10 04:00:00' , '2015-10-11 03:59:00' , 1000, 'CHF', 440, 'true', 8, 'STRIPE', 'alfio-uberall', 0, 'America/New_York', 'http://localhost:8080/resources/images/sample-logo.png');

insert into ticket_category(inception, expiration, name, description, max_tickets, price_cts, access_restricted, tc_status, event_id) values
('2014-01-10 00:00:00', '2015-10-10 00:00:00', 'Normal', 'Very good category', 2, 0, false, 'ACTIVE', 0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,50 @@ <h5>There are reservations for which a payment has not yet confirmed.</h5>
<i class="fa fa-dollar"></i> Pending payments <pending-reservations-badge data-event-name="{{event.shortName}}"></pending-reservations-badge>
</a>
</div>


<div data-ng-if="!event.free">
<div class="page-header">
<h3>Promo codes</h3>
<h5 class="text-muted">Manage/Handle the promo codes.</h5>
</div>
<div class="wMarginBottom">
<button type="button" class="btn btn-success" data-ng-click="addPromoCode(event)"><i class="fa fa-plus"></i> add promo code</button>
</div>
<div data-ng-repeat="promocode in promocodes" class="container wMarginBottom category-success">
<div class="page-header">
<div class="row">
<div class="col-sm-4">
<h4>{{::promocode.promoCode}}</h4>
</div>
<div class="col-sm-6">
<div class="row">
<div class="col-sm-4"><strong>Start validity</strong></div>
<div class="col-sm-8">{{::promocode.formattedStart | formatDate}} </div>
</div>
<div class="row">
<div class="col-sm-4"><strong>End validity</strong></div>
<div class="col-sm-8">{{::promocode.formattedEnd | formatDate}} </div>
</div>
<div class="row">
<div class="col-sm-4"><strong>Discount type</strong></div>
<div class="col-sm-8">{{::promocode.discountType}} </div>
</div>
<div class="row">
<div class="col-sm-4"><strong>Discount amount</strong></div>
<div class="col-sm-8">{{::promocode.discountAmount}} <span data-ng-if="promocode.discountType === 'PERCENTAGE'">%</span><span data-ng-if="promocode.discountType === 'FIXED_AMOUNT'">{{event.currency}}</span></div>
</div>
</div>
</div>
</div>
<div class="row wMarginBottom">
<div class="col-sm-4">
<button class="btn btn-warning" data-ng-click="deletePromocode(promocode)"><i class="fa fa-remove"></i> Delete</button>
</div>
</div>
</div>
</div>


<div class="page-header">
<h3>Categories</h3>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<div class="modal-header">
<h3>Insert new promo code</h3>
</div>
<form name="promoCodeForm" data-ng-submit="update(promoCodeForm, promocode, event)" novalidate data-error-sensitive>
<div class="modal-body">
<div class="col-sm-12 col-md-8 col-md-offset-2">
<div class="form-group">
<label for="promoCode">Promo code name</label>
<input type="text" id="promoCode" data-ng-model="promocode.promoCode" class="form-control to-uppercase" required minlength="7"/>
<field-error data-form-obj="promocode" data-field-obj="promocode.promoCode" data-show-existing-errors="showExistingErrors"></field-error>
</div>


<div class="form-group">
<label for="date">Validity range</label>
<input type="text" data-date-range data-start-model="promocode.start" data-end-model="promocode.end" data-ng-model="promocode.dateString" name="date" id="date" class="form-control" required />
<field-error data-form-obj="promocode" data-field-obj="promocode.dateString" data-show-existing-errors="showExistingErrors"></field-error>
</div>


<div class="form-group">
<label class="control-label">Discount type</label>
<div>
<div class="radio-inline">
<label>
<input type="radio" name="discountType" data-ng-model="promocode.discountType" data-ng-value="'FIXED_AMOUNT'" required>
Fixed amount
</label>
</div>
<div class="radio-inline">
<label>
<input type="radio" name="discountType" data-ng-model="promocode.discountType" data-ng-value="'PERCENTAGE'" required>
Percentage
</label>
</div>
</div>
</div>

<div class="form-group">
<label for="promoCode">Discount amount</label>
<div class="input-group">
<input type="number" id="discountAmount" data-ng-model="promocode.discountAmount" class="form-control" min="0"/>
<div class="input-group-addon">
<span data-ng-if="promocode.discountType === 'PERCENTAGE'">%</span>
<span data-ng-if="promocode.discountType === 'FIXED_AMOUNT'">{{event.currency}}</span>
</div>
</div>
<field-error data-form-obj="discountAmount" data-field-obj="promocode.discountAmount" data-show-existing-errors="showExistingErrors"></field-error>
</div>
</div>

<div class="clearfix"></div>
</div>

<div class="modal-footer">
<control-buttons data-form-obj="promoCodeForm"></control-buttons>
</div>
</form>
4 changes: 4 additions & 0 deletions src/main/webapp/resources/css/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,8 @@ div.wMarginBottom {

.drop-file-zone-hover {
border: 1px green dashed;
}

.to-uppercase {
text-transform: uppercase;
}
Loading

0 comments on commit 6ab7f4c

Please sign in to comment.