package module.webservice.api;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Set;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import module.finance.domain.SupplierContact;
import module.finance.util.Money;
import module.mission.domain.Mission;
import module.mission.domain.MissionProcess;
import module.mission.domain.RemoteMissionProcess;
import module.mission.domain.RemoteMissionSystem;
import module.mission.domain.activity.AssociateMissionProcessActivity;
import module.mission.domain.activity.AssociateMissionProcessActivityInfo;
import module.mission.domain.activity.DisassociateMissionProcessActivity;
import module.mission.domain.activity.DisassociateMissionProcessActivityInfo;
import module.mission.domain.util.SearchMissions;
import module.workflow.activities.ActivityInformation;
import module.workflow.activities.WorkflowActivity;
import module.workflow.domain.WorkflowProcess;
import module.workflow.domain.WorkflowSystem;
import org.fenixedu.bennu.core.domain.Bennu;
import org.fenixedu.bennu.core.domain.User;
import org.fenixedu.bennu.core.security.Authenticate;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pt.ist.expenditureTrackingSystem._development.ExpenditureConfiguration;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionItemClassification;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.CPVReference;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.afterthefact.AfterTheFactAcquisitionProcess;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.afterthefact.AfterTheFactAcquisitionType;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.afterthefact.activities.DeleteAfterTheFactAcquisitionProcess;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.afterthefact.activities.EditAfterTheFactProcessActivityInformation.AfterTheFactAcquisitionProcessBean;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.CancelAcquisitionRequest;
import pt.ist.expenditureTrackingSystem.domain.organization.Supplier;
import pt.ist.expenditureTrackingSystem.domain.util.DomainException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@Path("expenditures-tracking/v1")
public class ExpenditureAPIv1 {
private static final Logger logger = LoggerFactory.getLogger(ExpenditureAPIv1.class);
public final static String JSON_UTF8 = "application/json; charset=utf-8";
DateTimeFormatter formatDayHour = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm");
public static final DateTimeFormatter formatDay = DateTimeFormat.forPattern("dd/MM/yyyy");
public static final SimpleDateFormat dataFormatDay = new SimpleDateFormat("dd/MM/yyyy");
public static final SimpleDateFormat dataFormatHour = new SimpleDateFormat("HH:mm");
private static Gson gson;
static {
gson = new GsonBuilder().setPrettyPrinting().create();
}
@GET
@Produces(JSON_UTF8)
@Path("suppliers")
public String suppliers(@QueryParam("userID") String userID, @QueryParam("access_token") String access_token) {
checkToken(access_token);
Set<Supplier> suppliers = Bennu.getInstance().getSuppliersSet();
JsonArray toReturn = new JsonArray();
for (Supplier supplier : suppliers) {
if (supplier != null) {
JsonObject obj = new JsonObject();
obj.addProperty("supplierID", supplier.getExternalId());
obj.addProperty("fiscalID", supplier.getFiscalIdentificationCode());
obj.addProperty("name", supplier.getName());
obj.addProperty("shortName", supplier.getAbbreviatedName());
obj.addProperty("limit", supplier.getSupplierLimit().toFormatString());
JsonArray contacts = new JsonArray();
for (SupplierContact contact : supplier.getSupplierContactSet()) {
JsonObject contactObj = new JsonObject();
if (contact.getAddress() != null) {
JsonObject addressObj = new JsonObject();
addressObj.addProperty("line1", contact.getAddress().getLine1());
addressObj.addProperty("line2", contact.getAddress().getLine2());
addressObj.addProperty("country", contact.getAddress().getCountry());
contactObj.add("address", addressObj);
}
contactObj.addProperty("phone", contact.getPhone());
contactObj.addProperty("fax", contact.getFax());
contactObj.addProperty("email", contact.getEmail());
contacts.add(contactObj);
}
obj.add("contacts", contacts);
obj.addProperty("totalAllocated", supplier.getTotalAllocated().toFormatString());
JsonArray byCpv = new JsonArray();
for (CPVReference cpv : supplier.getAllocationsByCPVReference().keySet()) {
if (cpv != null) {
JsonObject cpvObj = new JsonObject();
cpvObj.addProperty("cpvCode", cpv.getCode());
cpvObj.addProperty("cpvDescription", cpv.getDescription());
cpvObj.addProperty("totalAllocated", supplier.getTotalAllocated(cpv).toFormatString());
byCpv.add(cpvObj);;
}
}
obj.add("allocationsByCPV", byCpv);
toReturn.add(obj);
}
}
return gson.toJson(toReturn);
}
@POST
@Produces(JSON_UTF8)
@Path("allocateFunds")
public Response allocateFunds(@QueryParam("supplierID") String supplierID, @QueryParam("value") String value,
@QueryParam("valueVat") String valueVAT, @QueryParam("cpvCode") String cpvcode,
@QueryParam("goodsOrService") String goodsOrServices, @QueryParam("description") String description,
@QueryParam("userID") String userID, @QueryParam("access_token") String access_token) {
checkToken(access_token);
login(User.findByUsername(userID));
try {
AfterTheFactAcquisitionProcessBean bean = new AfterTheFactAcquisitionProcessBean();
Set<Supplier> suppliers = Bennu.getInstance().getSuppliersSet();
Supplier supplier = null;
for (Supplier sup : suppliers) {
if (sup.getExternalId().equals(supplierID)) {
supplier = sup;
break;
}
}
if (supplier == null) {
return respondWithError(Status.NOT_FOUND, "supplier.not.found");
}
bean.setSupplier(supplier);
bean.setAfterTheFactAcquisitionType(AfterTheFactAcquisitionType.PURCHASE);
Money itemValue = new Money(value);
bean.setValue(itemValue);
double VAT = Double.parseDouble(valueVAT);
bean.setVatValue(new BigDecimal(VAT));
bean.setYear(new LocalDate().getYear());
bean.setDescription(description);
bean.setClassification(AcquisitionItemClassification.valueOf(goodsOrServices.toUpperCase()));
CPVReference cpvReference = CPVReference.getCPVCode(cpvcode);
if (cpvReference == null) {
return respondWithError(Status.NOT_FOUND, "cpv.reference.not.found");
}
bean.setCpvReference(cpvReference);
AfterTheFactAcquisitionProcess process;
try {
process = AfterTheFactAcquisitionProcess.createNewAfterTheFactAcquisitionProcess(bean);
} catch (DomainException e) {
throw newApplicationError(Status.PRECONDITION_FAILED, "precondition_failed");
}
JsonObject obj = new JsonObject();
obj.addProperty("processID", process.getProcessNumber());
return Response.ok().entity(gson.toJson(obj)).build();
} finally {
logout();
}
}
//change to put
@PUT
@Produces(JSON_UTF8)
@Path("cancelFundAllocation")
public String cancelFundAllocation(@QueryParam("processID") String processID, @QueryParam("userID") String userID,
@QueryParam("access_token") String access_token) {
checkToken(access_token);
login(User.findByUsername(userID));
try {
WorkflowSystem ws = WorkflowSystem.getInstance();
Set<WorkflowProcess> processes = ws.getProcessesSet();
for (WorkflowProcess workflowProcess : processes) {
if (workflowProcess.getProcessNumber() != null) {
if (workflowProcess.getProcessNumber().equals(processID)) {
WorkflowActivity<WorkflowProcess, ActivityInformation<WorkflowProcess>> cancelAcquisitionRequest =
workflowProcess.getActivity(DeleteAfterTheFactAcquisitionProcess.class.getSimpleName());
if (cancelAcquisitionRequest == null) { //is not after the fact
cancelAcquisitionRequest =
workflowProcess.getActivity(CancelAcquisitionRequest.class.getSimpleName());
}
try {
cancelAcquisitionRequest.execute(new ActivityInformation<WorkflowProcess>(workflowProcess,
cancelAcquisitionRequest));
} catch (Exception e) {
throw newApplicationError(Status.NOT_ACCEPTABLE, "cancelation_not_acceptable");
}
JsonObject obj = new JsonObject();
obj.addProperty("status", Status.OK.toString());
return gson.toJson(obj);
}
}
}
//No process was found
throw newApplicationError(Status.NOT_FOUND, "resource_not_found");
} finally {
logout();
}
}
@POST
@Produces(JSON_UTF8)
@Path("connectMissionProcess")
public Response connectMissionProcess(@QueryParam("processNumber") String processNumber,
@QueryParam("externalId") String externalId, @QueryParam("hostname") String hostname,
@QueryParam("remoteProcessNumber") String remoteProcessNumber, @QueryParam("username") String username,
@QueryParam("access_token") String access_token) {
checkToken(access_token);
try {
login(User.findByUsername(username));
final Mission mission = findMission(remoteProcessNumber);
if (mission == null) {
return respondWithError(Status.BAD_REQUEST, "bad.mission.number");
} else {
final MissionProcess missionProcess = mission.getMissionProcess();
final RemoteMissionSystem remoteMissionSystem = RemoteMissionSystem.find(hostname);
if (remoteMissionSystem == null) {
return respondWithError(Status.NOT_ACCEPTABLE, "remote.host.not.configured");
}
final AssociateMissionProcessActivity activity =
(AssociateMissionProcessActivity) missionProcess.getActivity(AssociateMissionProcessActivity.class);
final AssociateMissionProcessActivityInfo information = activity.getActivityInformation(missionProcess);
information.setProcessNumber(processNumber);
information.setExternalId(externalId);
information.setRemoteMissionSystem(remoteMissionSystem);
information.setConnect(false);
activity.execute(information);
final JsonObject obj = new JsonObject();
obj.addProperty("processID", missionProcess.getProcessNumber());
obj.addProperty("externalId", missionProcess.getExternalId());
return Response.ok().entity(gson.toJson(obj)).build();
}
} finally {
logout();
}
}
private Mission findMission(final String remoteProcessNumber) {
final SearchMissions search = new SearchMissions();
search.setProcessNumber(remoteProcessNumber);
final Set<Mission> missions = search.search();
if (missions.size() == 1) {
return missions.iterator().next();
}
return null;
}
@POST
@Produces(JSON_UTF8)
@Path("disconnectMissionProcess")
public Response disconnectMissionProcess(@QueryParam("processNumber") String processNumber,
@QueryParam("hostname") String hostname, @QueryParam("remoteProcessNumber") String remoteProcessNumber,
@QueryParam("username") String username, @QueryParam("access_token") String access_token) {
checkToken(access_token);
login(User.findByUsername(username));
try {
final Mission mission = findMission(remoteProcessNumber);
if (mission == null) {
return respondWithError(Status.BAD_REQUEST, "bad.mission.number");
} else {
final MissionProcess missionProcess = mission.getMissionProcess();
final RemoteMissionSystem remoteMissionSystem = RemoteMissionSystem.find(hostname);
if (remoteMissionSystem == null) {
return respondWithError(Status.NOT_ACCEPTABLE, "remote.host.not.configured");
}
for (final RemoteMissionProcess remoteMissionProcess : missionProcess.getRemoteMissionProcessSet()) {
if (remoteMissionProcess.getRemoteMissionSystem() == remoteMissionSystem
&& remoteMissionProcess.getProcessNumber().equals(processNumber)) {
final DisassociateMissionProcessActivity activity =
(DisassociateMissionProcessActivity) missionProcess
.getActivity(DisassociateMissionProcessActivity.class);
final DisassociateMissionProcessActivityInfo information =
activity.getActivityInformation(missionProcess);
information.setRemoteMissionProcess(remoteMissionProcess);
information.setConnect(false);
activity.execute(information);
}
}
return Response.ok().build();
}
} finally {
logout();
}
}
private void checkToken(String token) {
String storedToken = ExpenditureConfiguration.get().apiToken();
if (storedToken == null || !storedToken.equals(token)) {
throw newApplicationError(Status.FORBIDDEN, "can't access resource");
}
}
private void login(User user) {
if (user == null) {
throw newApplicationError(Status.BAD_REQUEST, "no user found");
}
Authenticate.mock(user);
}
private void logout() {
Authenticate.unmock();
}
private WebApplicationException newApplicationError(Status status, String error) {
return new WebApplicationException(status);
}
private Response respondWithError(final Status status, final String errorMessage) {
final JsonObject obj = new JsonObject();
obj.addProperty("error", errorMessage);
return Response.status(status).entity(gson.toJson(obj)).build();
}
}