Skip to content

Commit

Permalink
Supporting External Reference in List of Attendees Download (#1429)
Browse files Browse the repository at this point in the history
* Supporting External Reference in List of Attendees Download

Closes #1422

* Adding testing of CSV order of fields download

Closes #1422

* Refactoring test and improve sort order assertion

Closes #1422

* Removing unnecessary string join

Closes #1422
  • Loading branch information
dimitrisli authored Nov 24, 2024
1 parent 0658221 commit bc74e13
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,8 @@ public ResponseEntity<String> rearrangeCategories(@PathVariable String eventName
}

private static final String PAYMENT_METHOD = "Payment Method";
private static final List<String> FIXED_FIELDS = Arrays.asList("ID", "Category", "Event", "Status", "OriginalPrice", "PaidPrice", "Discount", "VAT", "ReservationID", "Full Name", "First Name", "Last Name", "E-Mail", "Locked", "Language", "Confirmation", "Billing Address", "Country Code", "Payment ID", PAYMENT_METHOD);
private static final String EXTERNAL_REFERENCE = "External Reference";
static final List<String> FIXED_FIELDS = Arrays.asList("ID", "Category", "Event", "Status", "OriginalPrice", "PaidPrice", "Discount", "VAT", "ReservationID", "Full Name", "First Name", "Last Name", "E-Mail", "Locked", "Language", "Confirmation", "Billing Address", "Country Code", "Payment ID", PAYMENT_METHOD, EXTERNAL_REFERENCE);
private static final List<SerializablePair<String, String>> FIXED_PAIRS = FIXED_FIELDS.stream().map(f -> SerializablePair.of(f, f)).collect(toList());
private static final String FISCAL_CODE = "Fiscal Code";
private static final String REFERENCE_TYPE = "Reference Type";
Expand Down Expand Up @@ -435,6 +436,7 @@ private Stream<String[]> exportLines(String eventName, Principal principal, List
if(paymentIdRequested) { line.add(Objects.toString(transaction.map(Transaction::getPaymentId).orElse(null), transaction.map(Transaction::getTransactionId).orElse(""))); }
if(paymentGatewayRequested) { line.add(transaction.map(tr -> tr.getPaymentProxy().name()).orElse("")); }
}
if(fields.contains(EXTERNAL_REFERENCE)) {line.add(t.getExtReference());}

if(eInvoicingEnabled) {
var billingDetails = trs.getBillingDetails();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,49 @@
import alfio.config.DataSourceConfiguration;
import alfio.config.Initializer;
import alfio.controller.api.ControllerConfiguration;
import alfio.manager.AdminReservationRequestManager;
import alfio.manager.EventManager;
import alfio.manager.user.UserManager;
import alfio.model.Event;
import alfio.model.TicketCategory;
import alfio.model.metadata.AlfioMetadata;
import alfio.model.modification.AdminReservationModification;
import alfio.model.modification.DateTimeModification;
import alfio.model.modification.TicketCategoryModification;
import alfio.repository.EventDeleterRepository;
import alfio.repository.EventRepository;
import alfio.repository.TicketCategoryRepository;
import alfio.repository.TicketRepository;
import alfio.repository.system.ConfigurationRepository;
import alfio.repository.user.OrganizationRepository;
import alfio.test.util.AlfioIntegrationTest;
import alfio.test.util.IntegrationTestUtil;
import alfio.util.ClockProvider;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.List;

import static alfio.controller.api.admin.EventApiController.FIXED_FIELDS;
import static alfio.test.util.IntegrationTestUtil.*;
import static alfio.test.util.TestUtil.clockProvider;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.when;

@AlfioIntegrationTest
Expand All @@ -73,8 +84,21 @@ class EventApiControllerIntegrationTest {
private EventDeleterRepository eventDeleterRepository;
@Autowired
private EventApiController eventApiController;
@Autowired
private AttendeeBulkImportApiController attendeeBulkImportApiController;
@Autowired
private AdminReservationRequestManager adminReservationRequestManager;
@Autowired
private TicketCategoryRepository ticketCategoryRepository;
@Autowired
private TicketRepository ticketRepository;

private Event event;
private static final String TEST_ATTENDEE_EXTERNAL_REFERENCE = "123";
private static final String TEST_ATTENDEE_USER_LANGUAGE = "en";
private static final String TEST_ATTENDEE_FIRST_NAME = "Attendee";
private static final String TEST_ATTENDEE_LAST_NAME = "Test";
private static final String TEST_ATTENDEE_EMAIL = "[email protected]";

@Test
void getAllEventsForExternalInPerson() {
Expand Down Expand Up @@ -119,6 +143,53 @@ void getAllEventsForExternalOnline() {
assertEquals(event.getShortName(), events.get(0).getKey());
}

@Test
void testGivenListOfAttendeesWithFieldsUploadThenSameFieldsAvailableOnCsvDownload() throws IOException {
// GIVEN - creation of event and registration of attendees
var eventAndUser = createEvent(Event.EventFormat.HYBRID);
event = eventAndUser.getKey();
var principal = Mockito.mock(Authentication.class);
when(principal.getName()).thenReturn(owner(eventAndUser.getValue()));
var modification = getTestAdminReservationModification();
var result = this.attendeeBulkImportApiController.createReservations(eventAndUser.getKey().getShortName(), modification, false, principal);

// GIVEN - invocation of async processing job
var requestStatus = this.attendeeBulkImportApiController.getRequestsStatus(eventAndUser.getKey().getShortName(), result.getData(), principal);
assertEquals(1, requestStatus.getData().getCountPending());

// WHEN - processing of pending reservations completes
this.adminReservationRequestManager.processPendingReservations();

// THEN - assert correctness of data persisted
var tickets = this.ticketRepository.findAllConfirmedForCSV(event.getId());
assertEquals(1, tickets.size());
var foundTicket = tickets.get(0).getTicket();
assertEquals(TEST_ATTENDEE_EXTERNAL_REFERENCE, foundTicket.getExtReference());
assertEquals(TEST_ATTENDEE_FIRST_NAME, foundTicket.getFirstName());
assertEquals(TEST_ATTENDEE_LAST_NAME, foundTicket.getLastName());
assertEquals(TEST_ATTENDEE_EMAIL, foundTicket.getEmail());
assertEquals(TEST_ATTENDEE_USER_LANGUAGE, foundTicket.getUserLanguage());

// THEN - assert correct order of CSV fields upon download
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
mockRequest.addParameter("fields", FIXED_FIELDS.toArray(new String[0]));
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
this.eventApiController.downloadAllTicketsCSV(event.getShortName(), "csv", mockRequest, mockResponse, principal);
String expectedTestAttendeeCsvLine = "\""+foundTicket.getUuid()+"\""+",default,"+"\""+event.getShortName()+"\""+",ACQUIRED,0,0,0,0,"+"\""+foundTicket.getTicketsReservationId()+"\""+",\""+TEST_ATTENDEE_FIRST_NAME+" "+TEST_ATTENDEE_LAST_NAME+"\","+TEST_ATTENDEE_FIRST_NAME+","+TEST_ATTENDEE_LAST_NAME+","+TEST_ATTENDEE_EMAIL+",false,"+TEST_ATTENDEE_USER_LANGUAGE;
String returnedCsvContent = mockResponse.getContentAsString().trim().replace("\uFEFF", ""); // remove BOM
assertTrue(returnedCsvContent.startsWith(getExpectedHeaderCsvLine() + "\n" + expectedTestAttendeeCsvLine));
assertTrue(returnedCsvContent.endsWith("\"Billing Address\",,,," + TEST_ATTENDEE_EXTERNAL_REFERENCE));
}

private AdminReservationModification getTestAdminReservationModification() {
DateTimeModification expiration = DateTimeModification.fromZonedDateTime(ZonedDateTime.now(ClockProvider.clock()).plusDays(1));
AdminReservationModification.CustomerData customerData = new AdminReservationModification.CustomerData("Integration", "Test", "[email protected]", "Billing Address", "reference", "en", "1234", "CH", null);
var ticketCategoryList = this.ticketCategoryRepository.findAllTicketCategories(event.getId());
AdminReservationModification.Category category = new AdminReservationModification.Category(ticketCategoryList.get(0).getId(), "name", new BigDecimal("100.00"), null);
List<AdminReservationModification.TicketsInfo> ticketsInfoList = Collections.singletonList(new AdminReservationModification.TicketsInfo(category, Collections.singletonList(generateTestAttendee()), true, false));
return new AdminReservationModification(expiration, customerData, ticketsInfoList, "en", false, false, null, null, null, null);
}

private Pair<Event,String> createEvent(Event.EventFormat format) {
IntegrationTestUtil.ensureMinimalConfiguration(configurationRepository);
List<TicketCategoryModification> categories = List.of(
Expand All @@ -131,6 +202,23 @@ private Pair<Event,String> createEvent(Event.EventFormat format) {

}

private String getExpectedHeaderCsvLine() {
String expectedHeaderCsvLine = String.join(",", FIXED_FIELDS);
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("Full Name", "\"Full Name\"");
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("First Name", "\"First Name\"");
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("Last Name", "\"Last Name\"");
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("Billing Address", "\"Billing Address\"");
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("Country Code", "\"Country Code\"");
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("Payment ID", "\"Payment ID\"");
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("Payment Method", "\"Payment Method\"");
expectedHeaderCsvLine = expectedHeaderCsvLine.replaceAll("External Reference", "\"External Reference\"");
return expectedHeaderCsvLine;
}

private AdminReservationModification.Attendee generateTestAttendee() {
return new AdminReservationModification.Attendee(null, TEST_ATTENDEE_FIRST_NAME, TEST_ATTENDEE_LAST_NAME, TEST_ATTENDEE_EMAIL, TEST_ATTENDEE_USER_LANGUAGE,false, TEST_ATTENDEE_EXTERNAL_REFERENCE, null, Collections.emptyMap(), null);
}

@AfterEach
void tearDown() {
eventDeleterRepository.deleteAllForEvent(event.getId());
Expand Down

0 comments on commit bc74e13

Please sign in to comment.