Skip to content

Commit

Permalink
fix #148: Improve VAT/Price management
Browse files Browse the repository at this point in the history
  • Loading branch information
cbellone committed Aug 5, 2016
1 parent 6a78703 commit f98ad93
Show file tree
Hide file tree
Showing 61 changed files with 1,423 additions and 637 deletions.
2 changes: 1 addition & 1 deletion src/main/java/alfio/controller/EventController.java
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ public String reserveTicket(@PathVariable("eventName") String eventName,
Date expiration = DateUtils.addMinutes(new Date(), ticketReservationManager.getReservationTimeout(event));

try {
String reservationId = ticketReservationManager.createTicketReservation(event.getId(),
String reservationId = ticketReservationManager.createTicketReservation(event,
selected.getLeft(), selected.getRight(), expiration,
SessionUtil.retrieveSpecialPriceSessionId(request.getRequest()),
SessionUtil.retrievePromotionCodeDiscount(request.getRequest()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ public ResponseEntity<EventModification.AdditionalService> update(@PathVariable(
Validate.isTrue(additionalServiceId == additionalService.getId(), "wrong input");
return optionally(() -> eventRepository.findById(eventId))
.map(event -> {
int result = additionalServiceRepository.update(additionalServiceId, Optional.ofNullable(additionalService.getPrice()).map(MonetaryUtil::unitToCents).orElse(0), additionalService.isFixPrice(),
int result = additionalServiceRepository.update(additionalServiceId, additionalService.isFixPrice(),
additionalService.getOrdinal(), additionalService.getAvailableQuantity(), additionalService.getMaxQtyPerOrder(), additionalService.getInception().toZonedDateTime(event.getZoneId()),
additionalService.getExpiration().toZonedDateTime(event.getZoneId()), additionalService.getVat(), additionalService.getVatType());
additionalService.getExpiration().toZonedDateTime(event.getZoneId()), additionalService.getVat(), additionalService.getVatType(), Optional.ofNullable(additionalService.getPrice()).map(MonetaryUtil::unitToCents).orElse(0));
Validate.isTrue(result <= 1, "too many records updated");
Stream.concat(additionalService.getTitle().stream(), additionalService.getDescription().stream()).
forEach(t -> additionalServiceTextRepository.update(t.getId(), t.getLocale(), t.getType(), t.getValue()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import alfio.repository.SponsorScanRepository;
import alfio.repository.TicketCategoryDescriptionRepository;
import alfio.repository.TicketFieldRepository;
import alfio.util.MonetaryUtil;
import alfio.util.ValidationResult;
import alfio.util.Validator;
import com.opencsv.CSVReader;
Expand Down Expand Up @@ -267,8 +268,10 @@ public void downloadAllTicketsCSV(@PathVariable("eventName") String eventName, H
if(fields.contains("category")) {line.add(categoriesMap.get(t.getCategoryId()).getName());}
if(fields.contains("event")) {line.add(eventName);}
if(fields.contains("status")) {line.add(t.getStatus().toString());}
if(fields.contains("originalPrice")) {line.add(t.getOriginalPrice().toString());}
if(fields.contains("paidPrice")) {line.add(t.getPaidPrice().toString());}
if(fields.contains("originalPrice")) {line.add(MonetaryUtil.centsToUnit(t.getSrcPriceCts()).toString());}
if(fields.contains("paidPrice")) {line.add(MonetaryUtil.centsToUnit(t.getFinalPriceCts()).toString());}
if(fields.contains("discount")) {line.add(MonetaryUtil.centsToUnit(t.getDiscountCts()).toString());}
if(fields.contains("vat")) {line.add(MonetaryUtil.centsToUnit(t.getVatCts()).toString());}
if(fields.contains("reservationID")) {line.add(t.getTicketsReservationId());}
if(fields.contains("Name")) {line.add(t.getFullName());}
if(fields.contains("E-Mail")) {line.add(t.getEmail());}
Expand Down
32 changes: 26 additions & 6 deletions src/main/java/alfio/controller/api/support/PublicCategory.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@
package alfio.controller.api.support;

import alfio.model.Event;
import alfio.model.PriceContainer;
import alfio.model.TicketCategory;
import alfio.model.TicketCategoryDescription;
import alfio.util.EventUtil;
import alfio.util.MonetaryUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.builder.CompareToBuilder;

Expand All @@ -29,12 +28,13 @@
import java.time.ZonedDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

import static java.lang.Math.max;
import static java.lang.Math.min;

public class PublicCategory {
public static Comparator<PublicCategory> SORT_BY_DATE = (c1, c2) -> new CompareToBuilder()
public class PublicCategory implements PriceContainer {
static Comparator<PublicCategory> SORT_BY_DATE = (c1, c2) -> new CompareToBuilder()
.append(c1.getUtcInception(), c2.getUtcInception())
.append(c1.getUtcExpiration(), c2.getUtcExpiration())
.toComparison();
Expand Down Expand Up @@ -90,8 +90,28 @@ public ZonedDateTime getExpiration() {
return getUtcExpiration().withZoneSameInstant(Clock.systemUTC().getZone());
}

public BigDecimal getFinalPrice() {
return MonetaryUtil.centsToUnit(EventUtil.getFinalPriceInCents(event, category));
@Override
@JsonIgnore
public int getSrcPriceCts() {
return category.getSrcPriceCts();
}

@Override
@JsonIgnore
public String getCurrencyCode() {
return event.getCurrency();
}

@Override
@JsonIgnore
public Optional<BigDecimal> getOptionalVatPercentage() {
return Optional.ofNullable(event.getVat());
}

@Override
@JsonIgnore
public VatStatus getVatStatus() {
return event.getVatStatus();
}

public int getMaxTickets() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,18 @@

import alfio.model.AdditionalService;
import alfio.model.Event;
import alfio.model.PriceContainer;
import alfio.model.PromoCodeDiscount;
import alfio.util.EventUtil;
import lombok.experimental.Delegate;

import java.math.BigDecimal;
import java.time.Clock;
import java.time.ZonedDateTime;
import java.util.Optional;

import static alfio.util.MonetaryUtil.formatCents;

public class SaleableAdditionalService {
public class SaleableAdditionalService implements PriceContainer {
private final Event event;
@Delegate(excludes = Exclusions.class)
@Delegate(excludes = {Exclusions.class, PriceContainer.class})
private final AdditionalService additionalService;
private final String title;
private final String description;
Expand Down Expand Up @@ -66,7 +64,7 @@ private static ZonedDateTime now() {
}

public boolean getFree() {
return isFixPrice() && getPriceInCents() == 0;
return isFixPrice() && getFinalPrice().compareTo(BigDecimal.ZERO) == 0;
}

public boolean getSaleable() {
Expand All @@ -81,12 +79,47 @@ public ZonedDateTime getZonedExpiration() {
return getExpiration(event.getZoneId());
}

public String getFinalPrice() {
return formatCents(getFinalPriceInCents());
@Override
public int getSrcPriceCts() {
return Optional.ofNullable(additionalService.getSrcPriceCts()).orElse(0);
}

@Override
public Optional<PromoCodeDiscount> getDiscount() {
return Optional.ofNullable(promoCodeDiscount);
}

@Override
public String getCurrencyCode() {
return event.getCurrency();
}

private int getFinalPriceInCents() {
return EventUtil.getFinalPriceInCents(event, additionalService);
@Override
public Optional<BigDecimal> getOptionalVatPercentage() {
if(getVatStatus() != VatStatus.NONE) {
return Optional.ofNullable(event.getVat()); //FIXME implement VAT override
}
return Optional.of(BigDecimal.ZERO);
}

@Override
public VatStatus getVatStatus() {
switch (getVatType()) {
case INHERITED:
return event.getVatStatus();
case NONE:
return VatStatus.NONE;
case CUSTOM_EXCLUDED:
return VatStatus.NOT_INCLUDED;
case CUSTOM_INCLUDED:
return VatStatus.INCLUDED;
default:
return VatStatus.NOT_INCLUDED;
}
}

public String getFormattedFinalPrice() {
return getFinalPrice().add(getAppliedDiscount()).toPlainString();
}

public boolean getSupportsDiscount() {
Expand All @@ -98,7 +131,7 @@ public boolean getUserDefinedPrice() {
}

public String getDiscountedPrice() {
return Optional.ofNullable(promoCodeDiscount).map(d -> formatCents(DecoratorUtil.calcDiscount(d, getFinalPriceInCents()))).orElseGet(this::getFinalPrice);
return getFinalPrice().toPlainString();
}

public boolean getVatIncluded() {
Expand All @@ -109,7 +142,7 @@ public boolean getVatIncluded() {
case CUSTOM_EXCLUDED:
return false;
case CUSTOM_INCLUDED:
return false;
return true;
default:
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@
package alfio.controller.decorator;

import alfio.model.Event;
import alfio.model.PriceContainer;
import alfio.model.PromoCodeDiscount;
import alfio.model.TicketCategory;
import alfio.util.EventUtil;
import lombok.experimental.Delegate;

import java.math.BigDecimal;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

import static alfio.util.MonetaryUtil.formatCents;

public class SaleableTicketCategory {
public class SaleableTicketCategory implements PriceContainer {

@Delegate
private final TicketCategory ticketCategory;
Expand Down Expand Up @@ -99,12 +98,28 @@ public ZonedDateTime getZonedInception() {
return getInception(zoneId);
}

public String getFinalPrice() {
return formatCents(getFinalPriceInCents());
@Override
public Optional<PromoCodeDiscount> getDiscount() {
return Optional.ofNullable(promoCodeDiscount);
}

@Override
public String getCurrencyCode() {
return event.getCurrency();
}

@Override
public Optional<BigDecimal> getOptionalVatPercentage() {
return Optional.ofNullable(event.getVat());
}

private int getFinalPriceInCents() {
return EventUtil.getFinalPriceInCents(event, ticketCategory);
@Override
public VatStatus getVatStatus() {
return event.getVatStatus();
}

public String getFormattedFinalPrice() {
return getFinalPriceToDisplay(getFinalPrice().add(getAppliedDiscount()), getVAT(), getVatStatus()).toString();
}

public int[] getAmountOfTickets() {
Expand All @@ -116,7 +131,7 @@ public int getAvailableTickets() {
}

public String getDiscountedPrice() {
return Optional.ofNullable(promoCodeDiscount).map(d -> formatCents(DecoratorUtil.calcDiscount(d, getFinalPriceInCents()))).orElseGet(this::getFinalPrice);
return getFinalPriceToDisplay(getFinalPrice(), getVAT(), getVatStatus()).toString();
}

public boolean getSupportsDiscount() {
Expand All @@ -127,5 +142,12 @@ public PromoCodeDiscount getPromoCodeDiscount() {
return promoCodeDiscount;
}

private static BigDecimal getFinalPriceToDisplay(BigDecimal price, BigDecimal vat, VatStatus vatStatus) {
if(vatStatus == VatStatus.NOT_INCLUDED) {
return price.subtract(vat);
}
return price;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public boolean hasBeenPaid() {
}

public boolean isFree() {
return getPaidPriceInCents() == 0;
return getFinalPriceCts() == 0;
}

public boolean getCancellationEnabled() {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/alfio/manager/CheckInManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ private TicketAndCheckInResult extractStatus(Optional<Event> maybeEvent, Optiona
final TicketStatus ticketStatus = ticket.getStatus();

if (ticketStatus == TicketStatus.TO_BE_PAID) {
return new TicketAndCheckInResult(ticket, new OnSitePaymentResult(MUST_PAY, "Must pay for ticket", MonetaryUtil.addVAT(ticket.getOriginalPrice(), event.getVat()), event.getCurrency()));
return new TicketAndCheckInResult(ticket, new OnSitePaymentResult(MUST_PAY, "Must pay for ticket", MonetaryUtil.addVAT(MonetaryUtil.centsToUnit(ticket.getFinalPriceCts()), event.getVat()), event.getCurrency()));
}

if (ticketStatus == TicketStatus.CHECKED_IN) {
Expand Down
Loading

0 comments on commit f98ad93

Please sign in to comment.