Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/load/BillingProfile.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
externalID ,clientCorporation.externalID,billingClientCorporation.externalID,billingContact.externalID,billingLocation.externalID,invoiceStatementMessageTemplate.name ,invoiceTerm.externalID,effectiveDate,title ,billingAttention,owner.name ,billingCorporateUser.name,description ,toRecipients ,ccRecipients ,bccRecipients ,status,isDeleted,customDate1,customDate2,customDate3,customFloat1,customFloat2,customFloat3,customInt1,customInt2,customInt3,customText1 ,customText2 ,customText3 ,customText4 ,customText5 ,customText6 ,customText7 ,customText8 ,customText9 ,customText10 ,customText11 ,customText12 ,customText13 ,customText14 ,customText15 ,customText16 ,customText17 ,customText18 ,customText19 ,customText20 ,customTextBlock1 ,customTextBlock2 ,customTextBlock3
billingProfile-ext-1,clientCorporation-ext-1 ,clientCorporation-ext-1 ,clientContact-ext-1 ,location-ext-1 ,invoiceStatementMessageTemplate-ext-1,invoiceTerm-ext-1 ,2001-01-01 ,Contractor,Frank ,Sales CorporateUser,Manager CorporateUser ,Billed to Client,[email protected],[email protected],[email protected],Active,FALSE ,1/1/16 0:00,1/2/16 0:00,1/3/16 0:00,1 ,2 ,3 ,1 ,1 ,3 ,billingProfile-ext-1,custom text field 20,custom text field 3,custom text field 4,custom text field 5,custom text field 6,custom text field 7,custom text field 8,custom text field 9,custom text field 10,custom text field 11,custom text field 12,custom text field 13,custom text field 14,custom text field 15,custom text field 16,custom text field 17,custom text field 18,custom text field 19,custom text field 1,custom text block 1,custom text block 2,custom text block 3
externalID ,clientCorporation.externalID,billingClientCorporation.externalID,billingContact.externalID,billingLocation.externalID,invoiceStatementMessageTemplate.name ,invoiceTerm.externalID,deliveryMethodLookup,effectiveDate,title ,billingAttention,owner.name ,billingCorporateUser.name,description ,toRecipients ,ccRecipients ,bccRecipients ,status,isDeleted,customDate1,customDate2,customDate3,customFloat1,customFloat2,customFloat3,customInt1,customInt2,customInt3,customText1 ,customText2 ,customText3 ,customText4 ,customText5 ,customText6 ,customText7 ,customText8 ,customText9 ,customText10 ,customText11 ,customText12 ,customText13 ,customText14 ,customText15 ,customText16 ,customText17 ,customText18 ,customText19 ,customText20 ,customTextBlock1 ,customTextBlock2 ,customTextBlock3
billingProfile-ext-1,clientCorporation-ext-1 ,clientCorporation-ext-1 ,clientContact-ext-1 ,location-ext-1 ,invoiceStatementMessageTemplate-ext-1,invoiceTerm-ext-1 ,3 ,2001-01-01 ,Contractor,Frank ,Sales CorporateUser,Manager CorporateUser ,Billed to Client,[email protected],[email protected],[email protected],Active,FALSE ,1/1/16 0:00,1/2/16 0:00,1/3/16 0:00,1 ,2 ,3 ,1 ,1 ,3 ,billingProfile-ext-1,custom text field 20,custom text field 3,custom text field 4,custom text field 5,custom text field 6,custom text field 7,custom text field 8,custom text field 9,custom text field 10,custom text field 11,custom text field 12,custom text field 13,custom text field 14,custom text field 15,custom text field 16,custom text field 17,custom text field 18,custom text field 19,custom text field 1,custom text block 1,custom text block 2,custom text block 3
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<dependency>
<groupId>com.bullhorn</groupId>
<artifactId>sdk-rest</artifactId>
<version>2.4.3</version>
<version>2.5.3</version>
<classifier>jdk8</classifier>
</dependency>

Expand Down
16 changes: 12 additions & 4 deletions src/main/java/com/bullhorn/dataloader/task/LoadTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class LoadTask extends AbstractTask {
private BullhornEntity entity;
private boolean isNewEntity = true;
private Record record;
private boolean hasDirectFieldsToPopulate = false;

public LoadTask(EntityInfo entityInfo,
Row row,
Expand All @@ -72,7 +73,12 @@ record = new Record(entityInfo, row, propertyFileUtil);

populateFields();
insertAttachmentToDescription();
insertOrUpdateEntity();

// Only call insertOrUpdateEntity if there are direct fields to persist, or if it's a new entity
if (isNewEntity || hasDirectFieldsToPopulate) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These code changes look good, and I see the addition of the example for the integration test, but I don't see any new unit tests for this new functionality. You probably want to add unit tests for billing profile and entities without direct fields to populate.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unit tests have been added @ndickerson

insertOrUpdateEntity();
}

createAssociations();
return isNewEntity ? Result.insert(entityId) : Result.update(entityId);
}
Expand Down Expand Up @@ -119,16 +125,18 @@ private void insertOrUpdateEntity() {
private void populateFields() throws Exception {
for (Field field : record.getFields()) {
if (field.isToMany()) {
if (entityInfo == EntityInfo.NOTE) {
if (entityInfo == EntityInfo.NOTE || entityInfo == EntityInfo.BILLING_PROFILE) {
prepopulateAssociation(field);
}
} else if (field.isToOne()) {
if (!field.getStringValue().isEmpty()) {
BullhornEntity toOneEntity = findToOneEntity(field);
field.populateAssociationOnEntity(entity, toOneEntity);
hasDirectFieldsToPopulate = true;
}
} else {
field.populateFieldOnEntity(entity);
hasDirectFieldsToPopulate = true;
}
}
}
Expand Down Expand Up @@ -175,8 +183,8 @@ private void prepopulateAssociation(Field field) throws IllegalAccessException,
*/
@SuppressWarnings("unchecked")
private void createAssociations() throws IllegalAccessException, InvocationTargetException {
// Note associations are filled out in the create call
if (entityInfo == EntityInfo.NOTE) {
// Note and BillingProfile associations are filled out in the create call
if (entityInfo == EntityInfo.NOTE || entityInfo == EntityInfo.BILLING_PROFILE) {
return;
}

Expand Down
26 changes: 14 additions & 12 deletions src/main/java/com/bullhorn/dataloader/util/AssociationUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.bullhornsdk.data.model.entity.association.AssociationFactory;
import com.bullhornsdk.data.model.entity.association.AssociationField;
import com.bullhornsdk.data.model.entity.association.EntityAssociations;
import com.bullhornsdk.data.model.entity.core.paybill.BillingProfile;
import com.bullhornsdk.data.model.entity.core.standard.Candidate;
import com.bullhornsdk.data.model.entity.core.standard.Category;
import com.bullhornsdk.data.model.entity.core.standard.ClientContact;
Expand Down Expand Up @@ -142,17 +143,18 @@ public static Boolean isToMany(EntityInfo entityInfo, String associationBaseName
* @return The associations list
*/
private static synchronized EntityAssociations getEntityAssociations(EntityInfo entityInfo) {
return (entityInfo.getEntityClass() == Candidate.class ? AssociationFactory.candidateAssociations() :
(entityInfo.getEntityClass() == Category.class ? AssociationFactory.categoryAssociations() :
(entityInfo.getEntityClass() == ClientContact.class ? AssociationFactory.clientContactAssociations() :
(entityInfo.getEntityClass() == ClientCorporation.class ? AssociationFactory.clientCorporationAssociations() :
(entityInfo.getEntityClass() == CorporateUser.class ? AssociationFactory.corporateUserAssociations() :
(entityInfo.getEntityClass() == JobOrder.class ? AssociationFactory.jobOrderAssociations() :
(entityInfo.getEntityClass() == Note.class ? AssociationFactory.noteAssociations() :
(entityInfo.getEntityClass() == Placement.class ? AssociationFactory.placementAssociations() :
(entityInfo.getEntityClass() == Opportunity.class ? AssociationFactory.opportunityAssociations() :
(entityInfo.getEntityClass() == Lead.class ? AssociationFactory.leadAssociations() :
entityInfo.getEntityClass() == Tearsheet.class ? AssociationFactory.tearsheetAssociations()
: null))))))))));
return (entityInfo.getEntityClass() == BillingProfile.class ? AssociationFactory.billingProfileAssociations() :
(entityInfo.getEntityClass() == Candidate.class ? AssociationFactory.candidateAssociations() :
(entityInfo.getEntityClass() == Category.class ? AssociationFactory.categoryAssociations() :
(entityInfo.getEntityClass() == ClientContact.class ? AssociationFactory.clientContactAssociations() :
(entityInfo.getEntityClass() == ClientCorporation.class ? AssociationFactory.clientCorporationAssociations() :
(entityInfo.getEntityClass() == CorporateUser.class ? AssociationFactory.corporateUserAssociations() :
(entityInfo.getEntityClass() == JobOrder.class ? AssociationFactory.jobOrderAssociations() :
(entityInfo.getEntityClass() == Note.class ? AssociationFactory.noteAssociations() :
(entityInfo.getEntityClass() == Placement.class ? AssociationFactory.placementAssociations() :
(entityInfo.getEntityClass() == Opportunity.class ? AssociationFactory.opportunityAssociations() :
(entityInfo.getEntityClass() == Lead.class ? AssociationFactory.leadAssociations() :
entityInfo.getEntityClass() == Tearsheet.class ? AssociationFactory.tearsheetAssociations()
: null)))))))))));
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/bullhorn/dataloader/util/MethodUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.bullhorn.dataloader.enums.ErrorInfo;

import com.bullhornsdk.data.model.entity.core.paybill.optionslookup.SimplifiedOptionsLookup;
import com.bullhornsdk.data.model.entity.core.paybill.optionslookup.SpecializedOptionsLookup;

/**
* Utility for low level method related methods used in DataLoader
Expand Down Expand Up @@ -173,6 +174,10 @@ public static Object convertStringToObject(String value, Class type, DateTimeFor
SimplifiedOptionsLookup simplifiedOptionsLookup = new SimplifiedOptionsLookup();
simplifiedOptionsLookup.setId(Integer.parseInt(value));
return simplifiedOptionsLookup;
} else if (SpecializedOptionsLookup.class.isAssignableFrom(type)) {
SpecializedOptionsLookup specializedOptionsLookup = new SpecializedOptionsLookup();
specializedOptionsLookup.setId(Integer.parseInt(value));
return specializedOptionsLookup;
}

return null;
Expand Down
110 changes: 108 additions & 2 deletions src/test/java/com/bullhorn/dataloader/task/LoadTaskTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import com.bullhornsdk.data.model.entity.association.standard.CandidateAssociations;
import com.bullhornsdk.data.model.entity.core.customobjectinstances.clientcorporation.ClientCorporationCustomObjectInstance2;
import com.bullhornsdk.data.model.entity.core.customobjectinstances.person.PersonCustomObjectInstance2;
import com.bullhornsdk.data.model.entity.core.paybill.BillingProfile;
import com.bullhornsdk.data.model.entity.core.paybill.invoice.InvoiceStatement;
import com.bullhornsdk.data.model.entity.core.standard.Appointment;
import com.bullhornsdk.data.model.entity.core.standard.AppointmentAttendee;
import com.bullhornsdk.data.model.entity.core.standard.BusinessSector;
Expand Down Expand Up @@ -934,8 +936,13 @@ public void testRunCatchNullPointerException() throws Exception {
restApiMock, printUtilMock, actionTotalsMock, cacheMock, completeUtilMock);
task.run();

Result expectedResult = Result.failure(new DataLoaderException(ErrorInfo.NULL_POINTER_EXCEPTION, ""));
verify(csvFileWriterMock, times(1)).writeRow(any(), eq(expectedResult));
ArgumentCaptor<Result> resultCaptor = ArgumentCaptor.forClass(Result.class);
verify(csvFileWriterMock, times(1)).writeRow(any(), resultCaptor.capture());
Result result = resultCaptor.getValue();
Assert.assertEquals(Result.Status.FAILURE, result.getStatus());
Assert.assertEquals(Result.Action.FAILURE, result.getAction());
Assert.assertEquals(ErrorInfo.NULL_POINTER_EXCEPTION, result.getErrorInfo());
Assert.assertEquals(-1, result.getBullhornId().intValue());
}

@Test
Expand Down Expand Up @@ -1559,4 +1566,103 @@ public void testRunInternetConnectivityIssues() throws Exception {
internetConnectivityIssueException.getMessage()));
verify(csvFileWriterMock, times(1)).writeRow(any(), eq(expectedResult));
}

@Test
public void testRunBillingProfileInsertSuccess() throws Exception {
Row row = TestUtils.createRow("externalID,billingContact.id", "1,2");
when(restApiMock.searchForList(eq(ClientContact.class), any(), any(), any()))
.thenReturn(TestUtils.getList(ClientContact.class, 2));
when(restApiMock.insertEntity(any())).thenReturn(TestUtils.getResponse(ChangeType.INSERT, 1));

LoadTask task = new LoadTask(EntityInfo.BILLING_PROFILE, row, csvFileWriterMock,
propertyFileUtilMock, restApiMock, printUtilMock, actionTotalsMock, cacheMock, completeUtilMock);
task.run();

verify(restApiMock, times(1)).insertEntity(any());
verify(restApiMock, never()).updateEntity(any());
verify(csvFileWriterMock, times(1)).writeRow(any(), eq(Result.insert(1)));
TestUtils.verifyActionTotals(actionTotalsMock, Result.Action.INSERT, 1);
}

@Test
public void testRunBillingProfileUpdateSuccess() throws Exception {
Row row = TestUtils.createRow("externalID,billingContact.externalID", "1,2");
when(propertyFileUtilMock.getEntityExistFields(EntityInfo.BILLING_PROFILE))
.thenReturn(Collections.singletonList("externalID"));
when(restApiMock.queryForList(eq(BillingProfile.class), any(), any(), any()))
.thenReturn(TestUtils.getList(BillingProfile.class, 1));
when(restApiMock.searchForList(eq(ClientContact.class),any(), any(), any()))
.thenReturn(TestUtils.getList(ClientContact.class, 2));

when(restApiMock.updateEntity(any())).thenReturn(TestUtils.getResponse(ChangeType.UPDATE, 1));

LoadTask task = new LoadTask(EntityInfo.BILLING_PROFILE, row, csvFileWriterMock,
propertyFileUtilMock, restApiMock, printUtilMock, actionTotalsMock, cacheMock, completeUtilMock);
task.run();

verify(restApiMock, times(1)).updateEntity(any());
verify(restApiMock, never()).insertEntity(any());
verify(csvFileWriterMock, times(1)).writeRow(any(), eq(Result.update(1)));
TestUtils.verifyActionTotals(actionTotalsMock, Result.Action.UPDATE, 1);
}

@Test
public void testUpdateWithoutDirectFieldsSkipsInsertOrUpsertEntity() throws Exception {
Row row = TestUtils.createRow("id, businessSectors.id", "1,33");
when(propertyFileUtilMock.getEntityExistFields(EntityInfo.JOB_ORDER))
.thenReturn(Collections.singletonList("id"));
when(restApiMock.searchForList(eq(JobOrder.class), any(), any(), any()))
.thenReturn(TestUtils.getList(JobOrder.class, 1));
when(restApiMock.queryForList(eq(BusinessSector.class), any(), any(), any()))
.thenReturn(TestUtils.getList(BusinessSector.class, 33));

LoadTask task = new LoadTask(EntityInfo.JOB_ORDER, row, csvFileWriterMock,
propertyFileUtilMock, restApiMock, printUtilMock, actionTotalsMock, cacheMock, completeUtilMock);
task.run();

verify(restApiMock, never()).insertEntity(any());
verify(restApiMock, never()).updateEntity(any());
}

@Test
public void testRunInsertEntityWithDirectFields() throws Exception {
Row row = TestUtils.createRow("firstName,lastName,primarySkills.id", "Data,Loader,1;2;3");
when(restApiMock.queryForList(eq(Skill.class), eq("(id=1 OR id=2 OR id=3)"), any(), any()))
.thenReturn(TestUtils.getList(Skill.class, 1, 2, 3));
when(restApiMock.insertEntity(any())).thenReturn(TestUtils.getResponse(ChangeType.INSERT, 1));

LoadTask task = new LoadTask(EntityInfo.CANDIDATE, row, csvFileWriterMock,
propertyFileUtilMock, restApiMock, printUtilMock, actionTotalsMock, cacheMock, completeUtilMock);
task.run();

verify(restApiMock, times(1)).insertEntity(any());
verify(restApiMock, never()).updateEntity(any());
verify(restApiMock, times(1)).associateWithEntity(eq(Candidate.class), eq(1),
eq(CandidateAssociations.getInstance().primarySkills()), eq(Arrays.asList(1, 2, 3)));
verify(csvFileWriterMock, times(1)).writeRow(any(), eq(Result.insert(1)));
TestUtils.verifyActionTotals(actionTotalsMock, Result.Action.INSERT, 1);
}

@Test
public void testRunUpdateEntityWithDirectFields() throws Exception {
Row row = TestUtils.createRow("externalID,firstName,primarySkills.id", "11,UpdatedName,1;2;3");
when(propertyFileUtilMock.getEntityExistFields(EntityInfo.CANDIDATE))
.thenReturn(Collections.singletonList("externalID"));
when(restApiMock.searchForList(eq(Candidate.class), eq("externalID:\"11\""), any(), any()))
.thenReturn(TestUtils.getList(Candidate.class, 1));
when(restApiMock.queryForList(eq(Skill.class), eq("(id=1 OR id=2 OR id=3)"), any(), any()))
.thenReturn(TestUtils.getList(Skill.class, 1, 2, 3));
when(restApiMock.updateEntity(any())).thenReturn(TestUtils.getResponse(ChangeType.UPDATE, 1));

LoadTask task = new LoadTask(EntityInfo.CANDIDATE, row, csvFileWriterMock,
propertyFileUtilMock, restApiMock, printUtilMock, actionTotalsMock, cacheMock, completeUtilMock);
task.run();

verify(restApiMock, never()).insertEntity(any());
verify(restApiMock, times(1)).updateEntity(any());
verify(restApiMock, times(1)).associateWithEntity(eq(Candidate.class), eq(1),
eq(CandidateAssociations.getInstance().primarySkills()), eq(Arrays.asList(1, 2, 3)));
verify(csvFileWriterMock, times(1)).writeRow(any(), eq(Result.update(1)));
TestUtils.verifyActionTotals(actionTotalsMock, Result.Action.UPDATE, 1);
}
}