Author: ymartel Date: 2014-07-16 16:25:50 +0200 (Wed, 16 Jul 2014) New Revision: 422 Url: http://forge.chorem.org/projects/chorem/repository/revisions/422 Log: prepare ExpenseAccount : now, partial save and display Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonConverter.java trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonHelper.java trunk/chorem-webmotion/src/test/ trunk/chorem-webmotion/src/test/java/ trunk/chorem-webmotion/src/test/java/org/ trunk/chorem-webmotion/src/test/java/org/chorem/ trunk/chorem-webmotion/src/test/java/org/chorem/webmotion/ trunk/chorem-webmotion/src/test/java/org/chorem/webmotion/converters/ trunk/chorem-webmotion/src/test/java/org/chorem/webmotion/converters/JsonConverterTest.java trunk/chorem-webmotion/src/test/resources/ trunk/chorem-webmotion/src/test/resources/log4j.properties Modified: trunk/chorem-entities/src/main/xmi/chorem-model.properties trunk/chorem-entities/src/main/xmi/chorem-model.zargo trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/financial/ExpenseAccountAction.java trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountBean.java trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountEntryBean.java trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/injector/InjectorListener.java trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountEntryEdit.html trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountView.jsp trunk/chorem-webmotion/src/main/webapp/js/financial/expenseAccount.js Modified: trunk/chorem-entities/src/main/xmi/chorem-model.properties =================================================================== --- trunk/chorem-entities/src/main/xmi/chorem-model.properties 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-entities/src/main/xmi/chorem-model.properties 2014-07-16 14:25:50 UTC (rev 422) @@ -192,7 +192,7 @@ # ExpenseAccount # org.chorem.entities.ExpenseAccount.class.tagvalue.version=1.0 -org.chorem.entities.ExpenseAccount.class.tagvalue.preload=ExpenseAccount.employee +org.chorem.entities.ExpenseAccount.class.tagvalue.preload=ExpenseAccount.employee;ExpenseAccount.org.chorem.entities.Employee.class.tagvalue.preload org.chorem.entities.ExpenseAccount.class.tagvalue.toString=%ExpenseAccount.employee$s - %Interval.beginDate$s/%Interval.endDate$s org.chorem.entities.ExpenseAccount.class.tagvalue.sortOrder=Interval.beginDate,Interval.endDate @@ -201,7 +201,7 @@ # org.chorem.entities.ExpenseAccountEntry.class.tagvalue.version=1.0 org.chorem.entities.ExpenseAccountEntry.class.tagvalue.toString=%FinancialTransaction.reference$tF-%ExpenseAccountEntry.justificationNumber$tF -org.chorem.entities.ExpenseAccountEntry.class.tagvalue.preload=FinancialTransaction.beneficiary;FinancialTransaction.category +org.chorem.entities.ExpenseAccountEntry.class.tagvalue.preload=FinancialTransaction.beneficiary;FinancialTransaction.category;FinancialTransaction.target org.chorem.entities.ExpenseAccountEntry.class.tagvalue.sortOrder=ExpenseAccountEntry.date # Modified: trunk/chorem-entities/src/main/xmi/chorem-model.zargo =================================================================== (Binary files differ) Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/financial/ExpenseAccountAction.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/financial/ExpenseAccountAction.java 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/financial/ExpenseAccountAction.java 2014-07-16 14:25:50 UTC (rev 422) @@ -23,9 +23,8 @@ * #L% */ -import java.util.ArrayList; -import java.util.Calendar; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Set; @@ -33,18 +32,16 @@ import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; -import com.google.gson.Gson; import org.apache.commons.lang3.StringUtils; import org.chorem.ChoremClient; import org.chorem.entities.Category; import org.chorem.entities.CategoryImpl; import org.chorem.entities.Employee; -import org.chorem.entities.EmployeeImpl; import org.chorem.entities.ExpenseAccount; import org.chorem.entities.ExpenseAccountEntry; import org.chorem.entities.ExpenseAccountEntryImpl; import org.chorem.entities.ExpenseAccountImpl; -import org.chorem.entities.Project; +import org.chorem.entities.Quotation; import org.chorem.webmotion.PaginatedResult; import org.chorem.webmotion.bean.financial.ExpenseAccountBean; import org.chorem.webmotion.bean.financial.ExpenseAccountEntryBean; @@ -61,22 +58,51 @@ */ public class ExpenseAccountAction extends WebMotionController { + /** + * Find all {@link org.chorem.entities.ExpenseAccount} and return their as a {@link org.chorem.webmotion.PaginatedResult} of {@code ExpenseAccountBean}. + * + * The result is paginated and can be filtered as following : + * <ul> + * <li>corresponding to a specific month/year : all expense accounts covering this month are returned ;</li> + * <li>corresponding to a specific year : in this case, all the ExpenseAccount covering a part of the year are returned;</li> + * <li>no year and no month given : in this case, all the ExpenseAccount covering current month are returned;</li> + * </ul> + * + * @param client + * @param year + * @param month + * @param page + * @param count + * @return + */ public PaginatedResult<ExpenseAccountBean> findAllExpenseAccounts(ChoremClient client, Integer year, Integer month, int page, int count) { - if (month == null) { - month = DateUtil.getMonth(new Date()); + Date refStartDate; + Date refEndDate; + + if (month == null && year != null) { + // only year is given : search for all year + refStartDate = DateUtil.createDate(1, 1, year); + refEndDate = DateUtil.createDate(31, 12, year); + + } else if (month == null && year == null) { + // no month, no year, give current month ? + Date today = new Date(); + refStartDate = DateUtil.setFirstDayOfMonth(today); + refEndDate = DateUtil.setLastDayOfMonth(today); + + } else { + // we have a month and a year : just search ones corresponding to this month + refStartDate = DateUtil.createDate(1, month, year); + refEndDate = DateUtil.setLastDayOfMonth(refStartDate); + } - if (year == null) { - Calendar calendar = Calendar.getInstance(); - year = calendar.get(Calendar.YEAR); - } - Date refDate = DateUtil.createDate(1, month, year); WikittyQuery totalQuery = new WikittyQueryMaker() .select().count(ExpenseAccount.ELEMENT_FIELD_INTERVAL_BEGINDATE).where().and() .exteq(ExpenseAccount.EXT_EXPENSEACCOUNT) - .le(ExpenseAccount.ELEMENT_FIELD_INTERVAL_BEGINDATE, refDate) - .ge(ExpenseAccount.ELEMENT_FIELD_INTERVAL_ENDDATE, refDate) + .le(ExpenseAccount.ELEMENT_FIELD_INTERVAL_BEGINDATE, refEndDate) + .ge(ExpenseAccount.ELEMENT_FIELD_INTERVAL_ENDDATE, refStartDate) .end(); Integer nbExpenseAccounts = client.findByQuery(Integer.class, totalQuery); @@ -87,8 +113,8 @@ WikittyQuery expAccountsQuery = new WikittyQueryMaker() .where().and() .exteq(ExpenseAccount.EXT_EXPENSEACCOUNT) - .le(ExpenseAccount.ELEMENT_FIELD_INTERVAL_BEGINDATE, refDate) - .ge(ExpenseAccount.ELEMENT_FIELD_INTERVAL_ENDDATE, refDate) + .le(ExpenseAccount.ELEMENT_FIELD_INTERVAL_BEGINDATE, refEndDate) + .ge(ExpenseAccount.ELEMENT_FIELD_INTERVAL_ENDDATE, refStartDate) .end() .setOffset((page - 1) * count) .setLimit(page * count); @@ -100,46 +126,29 @@ paginatedResult = new PaginatedResult<>(Lists.newArrayList(expenseAccountBeans), page, count, nbExpenseAccounts); } else { - - //XXX ymartel 2014/04/09 : create fake datas for test - Employee employee = client.findAllByExample(new EmployeeImpl(), 0, 1).get(0); - ExpenseAccountBean fakeOne = new ExpenseAccountBean(); - fakeOne.setId("fake"); - fakeOne.setStartDate(DateUtil.createDate(1, 3, 2014)); - fakeOne.setEndDate(DateUtil.createDate(31, 3, 2014)); - fakeOne.setEmployeeName(employee.toString()); - fakeOne.setEmployeeId(employee.getWikittyId()); - ExpenseAccountBean fakeTwo = new ExpenseAccountBean(); - fakeTwo.setId("fake"); - fakeTwo.setStartDate(DateUtil.createDate(1, 4, 2014)); - fakeTwo.setEndDate(DateUtil.createDate(30, 4, 2014)); - fakeTwo.setEmployeeName(employee.toString()); - fakeTwo.setEmployeeId(employee.getWikittyId()); - ArrayList<ExpenseAccountBean> expenseAccounts = new ArrayList<>(); - expenseAccounts.add(fakeOne); - expenseAccounts.add(fakeTwo); - paginatedResult = new PaginatedResult<>(expenseAccounts, 1, count, 0); + paginatedResult = new PaginatedResult<>(Collections.EMPTY_LIST, 1, 0, 0); } return paginatedResult; } - public void saveExpenseAccount(ChoremClient client, String expenseAccountId, ExpenseAccountBean expenseAccount) { + public void saveExpenseAccount(ChoremClient client, String expenseAccountId, ExpenseAccountBean expenseAccountBean) { + ExpenseAccountImpl expenseAccountWikitty = client.restore(ExpenseAccountImpl.class, expenseAccountId); - String employeeId = expenseAccount.getEmployeeId(); + String employeeId = expenseAccountBean.getEmployeeId(); Employee employee = client.restore(Employee.class, employeeId); if (expenseAccountWikitty == null) { expenseAccountWikitty = new ExpenseAccountImpl(); expenseAccountWikitty.setEmployee(employee); } - expenseAccountWikitty.setBeginDate(expenseAccount.getStartDate()); - expenseAccountWikitty.setEndDate(expenseAccount.getEndDate()); - Set<ExpenseAccountEntryBean> expenseAccountEntries = expenseAccount.getExpenseAccountEntries(); + expenseAccountWikitty.setBeginDate(expenseAccountBean.getStartDate()); + expenseAccountWikitty.setEndDate(expenseAccountBean.getEndDate()); + Set<ExpenseAccountEntryBean> expenseAccountEntries = expenseAccountBean.getExpenseAccountEntries(); if (expenseAccountEntries != null) { for (ExpenseAccountEntryBean expenseAccountEntryBean : expenseAccountEntries) { ExpenseAccountEntry expenseAccountEntry = new ExpenseAccountEntryImpl(); expenseAccountEntry.setReference(expenseAccountEntryBean.getJustificationNumber()); - expenseAccountEntry.setEmittedDate(new Date(expenseAccountEntryBean.getEmittedDate())); + expenseAccountEntry.setEmittedDate(new Date(expenseAccountEntryBean.getEmittedDate().getTime())); expenseAccountEntry.setDescription(expenseAccountEntryBean.getDescription()); expenseAccountEntry.setAmount(expenseAccountEntryBean.getAmount()); expenseAccountEntry.setVAT(expenseAccountEntryBean.getVAT()); @@ -177,7 +186,7 @@ } - Function<ExpenseAccount, ExpenseAccountBean> TRANSFORM_EXPENSE_ACCOUNT_TO_BEAN = new Function<ExpenseAccount, ExpenseAccountBean>() { + protected Function<ExpenseAccount, ExpenseAccountBean> TRANSFORM_EXPENSE_ACCOUNT_TO_BEAN = new Function<ExpenseAccount, ExpenseAccountBean>() { @Override public ExpenseAccountBean apply(ExpenseAccount expenseAccount) { ExpenseAccountBean expenseAccountBean = new ExpenseAccountBean(); @@ -188,7 +197,54 @@ expenseAccountBean.setStartDate(expenseAccount.getBeginDate()); expenseAccountBean.setEndDate(expenseAccount.getEndDate()); expenseAccountBean.setEndDate(expenseAccount.getEndDate()); + Set<ExpenseAccountEntry> expenseAccountEntries = expenseAccount.getExpenseAccountEntry(false); + for (ExpenseAccountEntry expenseAccountEntry : expenseAccountEntries) { + if (expenseAccountEntry != null) { + ExpenseAccountEntryBean expenseAccountEntryBean = TRANSFORM_EXPENSE_ACCOUNT_ENTRY_TO_BEAN.apply(expenseAccountEntry); + expenseAccountBean.addExpenseAccountEntry(expenseAccountEntryBean); + } + } return expenseAccountBean; } }; + + protected Function<ExpenseAccountEntry, ExpenseAccountEntryBean> TRANSFORM_EXPENSE_ACCOUNT_ENTRY_TO_BEAN = new Function<ExpenseAccountEntry, ExpenseAccountEntryBean>() { + + @Override + public ExpenseAccountEntryBean apply(ExpenseAccountEntry expenseAccountEntry) { + ExpenseAccountEntryBean expenseAccountEntryBean = new ExpenseAccountEntryBean(); + + Category category = expenseAccountEntry.getCategory(false); + if (category != null) { + expenseAccountEntryBean.setCategoryId(category.getWikittyId()); + expenseAccountEntryBean.setCategoryName(category.getName()); + } + + Date emittedDate = expenseAccountEntry.getEmittedDate(); + if (emittedDate != null) { + expenseAccountEntryBean.setEmittedDate(new Date(emittedDate.getTime())); + } + + Date paymentDate = expenseAccountEntry.getPaymentDate(); + if (paymentDate != null) { + expenseAccountEntryBean.setPaymentDate(new Date(paymentDate.getTime())); + } + + expenseAccountEntryBean.setDescription(expenseAccountEntry.getDescription()); + expenseAccountEntryBean.setJustificationNumber(expenseAccountEntry.getReference()); + + double amount = expenseAccountEntry.getAmount(); + double vat = expenseAccountEntry.getVAT(); + expenseAccountEntryBean.setAmount(amount); + expenseAccountEntryBean.setVAT(vat); + expenseAccountEntryBean.setTotal(amount + vat); + + Quotation quotation = expenseAccountEntry.getQuotation(false); + if (quotation != null) { + expenseAccountEntryBean.setProjectId(quotation.getWikittyId()); + expenseAccountEntryBean.setProjectName(quotation.toString()); + } + return expenseAccountEntryBean; + } + }; } Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountBean.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountBean.java 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountBean.java 2014-07-16 14:25:50 UTC (rev 422) @@ -25,6 +25,7 @@ import java.io.Serializable; import java.util.Date; +import java.util.HashSet; import java.util.Set; import com.google.gson.Gson; @@ -70,7 +71,7 @@ } public void setStartDate(Date startDate) { - this.startDate = startDate; + this.startDate = new Date(startDate.getTime()); } public Date getEndDate() { @@ -78,7 +79,7 @@ } public void setEndDate(Date endDate) { - this.endDate = endDate; + this.endDate = new Date(endDate.getTime()); } public Set<ExpenseAccountEntryBean> getExpenseAccountEntries() { @@ -89,6 +90,13 @@ this.expenseAccountEntries = expenseAccountEntries; } + public void addExpenseAccountEntry(ExpenseAccountEntryBean expenseAccountEntryBean) { + if (this.expenseAccountEntries == null) { + this.expenseAccountEntries = new HashSet<>(); + } + this.expenseAccountEntries.add(expenseAccountEntryBean); + } + public String toJson() { Gson gson = new Gson(); return gson.toJson(this); Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountEntryBean.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountEntryBean.java 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/bean/financial/ExpenseAccountEntryBean.java 2014-07-16 14:25:50 UTC (rev 422) @@ -24,6 +24,7 @@ */ import java.io.Serializable; +import java.util.Date; /** * @author ymartel (martel@codelutin.com) @@ -32,8 +33,8 @@ protected String categoryName; protected String categoryId; - protected long emittedDate; - protected long paymentDate; + protected Date emittedDate; + protected Date paymentDate; protected String description; protected String justificationNumber; protected Double amount; @@ -58,20 +59,20 @@ this.categoryId = categoryId; } - public long getEmittedDate() { + public Date getEmittedDate() { return emittedDate; } - public void setEmittedDate(long emittedDate) { - this.emittedDate = emittedDate; + public void setEmittedDate(Date emittedDate) { + this.emittedDate = new Date(emittedDate.getTime()); } - public long getPaymentDate() { + public Date getPaymentDate() { return paymentDate; } - public void setPaymentDate(long paymentDate) { - this.paymentDate = paymentDate; + public void setPaymentDate(Date paymentDate) { + this.paymentDate = new Date(paymentDate.getTime()); } public String getDescription() { Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonConverter.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonConverter.java (rev 0) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonConverter.java 2014-07-16 14:25:50 UTC (rev 422) @@ -0,0 +1,54 @@ +package org.chorem.webmotion.converters; + +import org.apache.commons.beanutils.converters.AbstractConverter; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class JsonConverter<O> extends AbstractConverter { + + protected Class<O> objectType; + + protected final JsonHelper jsonHelper; + + public static <O> JsonConverter<O> newConverter(Class<O> objectType) { + return new JsonConverter<>(objectType); + } + + public JsonConverter(Class<O> objectType) { + + this.objectType = objectType; + this.jsonHelper = new JsonHelper(); + } + + @Override + protected String convertToString(Object value) throws Throwable { + + String result = jsonHelper.toJson(value); + return result; + } + + @Override + protected <T> T convertToType(Class<T> type, Object value) throws Throwable { + + String stringValue; + + if (value instanceof String) { + + stringValue = (String) value; + + } else { + + stringValue = ((String[]) value)[0]; + } + + T result = (T) jsonHelper.fromJson(stringValue, type); + + return result; + } + + @Override + protected Class<O> getDefaultType() { + return this.objectType; + } +} Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonHelper.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonHelper.java (rev 0) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/converters/JsonHelper.java 2014-07-16 14:25:50 UTC (rev 422) @@ -0,0 +1,88 @@ +package org.chorem.webmotion.converters; + +import java.lang.reflect.Type; +import java.util.Date; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class JsonHelper { + + protected final Gson gson; + + public JsonHelper() { + + GsonBuilder gsonBuilder = new GsonBuilder(); + + gsonBuilder.setExclusionStrategies(new ExclusionStrategy() { + @Override + public boolean shouldSkipField(FieldAttributes f) { + return false; + } + + @Override + public boolean shouldSkipClass(Class<?> clazz) { + return clazz == Class.class; + } + }); + + gsonBuilder.registerTypeAdapter(Date.class, new JsonSerializer<Date>() { + + @Override + public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { + + JsonElement result; + + if (src == null) { + result = JsonNull.INSTANCE; + + } else { + result = new JsonPrimitive(src.getTime()); + } + + return result; + } + + }); + + gsonBuilder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() { + @Override + public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + return new Date(json.getAsLong()); + } + + }); + + this.gson = gsonBuilder.create(); + } + + public String toJson(Object model) { + String json = gson.toJson(model); + return json; + } + + public <O> O fromJson(String json, Class<O> type) { + O o = gson.fromJson(json, type); + return o; + } + + public <O> O fromJson(String json, Type type) { + O o = gson.fromJson(json, type); + return o; + } + + +} Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/injector/InjectorListener.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/injector/InjectorListener.java 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/injector/InjectorListener.java 2014-07-16 14:25:50 UTC (rev 422) @@ -23,20 +23,26 @@ package org.chorem.webmotion.injector; import java.lang.reflect.Array; -import org.chorem.ChoremClient; -import org.debux.webmotion.server.WebMotionServerListener; -import org.debux.webmotion.server.call.Call; -import org.debux.webmotion.server.call.ServerContext; -import org.debux.webmotion.server.handler.ExecutorParametersInjectorHandler.Injector; -import org.debux.webmotion.server.mapping.Mapping; - import java.lang.reflect.Type; import java.util.Collection; import java.util.Date; +import java.util.Set; + +import com.google.common.collect.Sets; import org.apache.commons.beanutils.ConversionException; import org.apache.commons.beanutils.Converter; import org.apache.commons.lang3.StringUtils; +import org.chorem.ChoremClient; import org.chorem.webmotion.ChoremWebMotionUtil; +import org.chorem.webmotion.PaginatedResult; +import org.chorem.webmotion.bean.financial.ExpenseAccountBean; +import org.chorem.webmotion.bean.financial.ExpenseAccountEntryBean; +import org.chorem.webmotion.converters.JsonConverter; +import org.debux.webmotion.server.WebMotionServerListener; +import org.debux.webmotion.server.call.Call; +import org.debux.webmotion.server.call.ServerContext; +import org.debux.webmotion.server.handler.ExecutorParametersInjectorHandler.Injector; +import org.debux.webmotion.server.mapping.Mapping; import org.nuiton.wikitty.WikittyUtil; /** @@ -44,6 +50,12 @@ */ public class InjectorListener implements WebMotionServerListener { + protected static final Set<Class<?>> BEAN_TYPES = Sets.<Class<?>>newHashSet( + ExpenseAccountBean.class, + ExpenseAccountEntryBean.class, + PaginatedResult.class + ); + @Override public void onStart(Mapping mpng, ServerContext context) { @@ -60,7 +72,6 @@ } }); - // ajout d'un converter pour support tous les formats de date (comme wikitty) context.addConverter(new Converter() { @Override @@ -98,6 +109,11 @@ return result; } }, Date.class); + + for (Class<?> beanType : BEAN_TYPES) { + context.addConverter(JsonConverter.newConverter(beanType), beanType); + } + } @Override Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountEntryEdit.html =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountEntryEdit.html 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountEntryEdit.html 2014-07-16 14:25:50 UTC (rev 422) @@ -1,7 +1,9 @@ <td><input type="text" ng-model="newExpenseAccountEntry.justificationNumber" name="newExpenseAccountEntry.justificationNumber" size="10" style='width:100%'></td> - <td><input type="date" ng-model="newExpenseAccountEntry.emittedDate" name="newExpenseAccountEntry.emittedDate" size="10" maxlength="10" style='width:90%'></td> <td> + <input class="form-control" type="text" ng-model="newExpenseAccountEntry.emittedDate" datepicker-popup="dd/MM/yyyy" is-open="emittedDateOpened" ng-click="emittedDateOpened = true" size="10" maxlength="10" style='width:90%'> + </td> + <td> <input type="text" ng-model="newExpenseAccountEntry.projectName" name="newExpenseAccountEntry.project" size="4" style='width:100%' id="text-newExpenseAccountEntry-project" auto-complete data-source="Project" data-model="newExpenseAccountEntry" data-base-field="project"> <input type="hidden" ng-model="newExpenseAccountEntry.projectId" id="hidden-newExpenseAccountEntry-project"/> </td> Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountView.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountView.jsp 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/financial/expenseAccountView.jsp 2014-07-16 14:25:50 UTC (rev 422) @@ -25,8 +25,6 @@ <%@ taglib uri="/WEB-INF/wikitty.tld" prefix="w"%> <head> - <script data-require="angular-resource@1.2.10" data-semver="1.2.10" src="<c:url value='http://code.angularjs.org/1.2.10/angular-resource.js'/>"></script> - <link data-require="bootstrap-css@*" data-semver="3.1.1" rel="stylesheet" href="<c:url value='http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css'/>" /> <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.js"></script> <script type="text/javascript" src="<c:url value='/js/financial/expenseAccount.js'/>"></script> @@ -40,17 +38,31 @@ </head> <div ng-app='expenseAccountPage' ng-controller="expenseAccountView"> - <div > - <dl> - <dd ng-if="expenseAccount && expenseAccount.employeeId"><a href="<c:url value="/wikitty/view/{{expenseAccount.employeeId}}"/>">{{expenseAccount.employeeName}}</a></dd> - <dd ng-if="!expenseAccount || !expenseAccount.employeeId"> - <input type="text" ng-model="expenseAccount.employeeName" id="text-expenseAccount-employee" auto-complete data-source="Employee" data-model="expenseAccount" data-base-field="employee" /> - <input type="hidden" ng-model="expenseAccount.employeeId" id="hidden-expenseAccount-employee"/> + <div > + <dl> + <dd ng-if="expenseAccount && expenseAccount.employeeId"><a href="<c:url value="/wikitty/view/{{expenseAccount.employeeId}}"/>">{{expenseAccount.employeeName}}</a></dd> + <dd ng-if="!expenseAccount || !expenseAccount.employeeId"> + <input type="text" ng-model="expenseAccount.employeeName" id="text-expenseAccount-employee" auto-complete data-source="Employee" data-model="expenseAccount" data-base-field="employee" /> + <input type="hidden" ng-model="expenseAccount.employeeId" id="hidden-expenseAccount-employee"/> + </dd> + <dd ng-if="editPeriod == false">Period from {{expenseAccount.startDate |date}} to {{expenseAccount.endDate |date}}</dd> + <dd ng-if="editPeriod == true"> + <label for="expenseAccountStartDate">Start Date :</label> + <input id="expenseAccountBeginDate" class="form-control" type="text" + datepicker-popup="dd/MM/yyyy" + ng-model="expenseAccount.startDate" + is-open="startDateOpened" + ng-click="startDateOpened = true" /> + </dd> + <dd ng-if="editPeriod == true"> + <label for="expenseAccountEndDate">EndDate :</label> + <input id="expenseAccountEndDate" class="form-control" type="text" + datepicker-popup="dd/MM/yyyy" + ng-model="expenseAccount.endDate" + is-open="endDateOpened" + ng-click="endDateOpened = true" /> - </dd> - <dd ng-if="editPeriod == false">Period from {{expenseAccount.startDate |date}} to {{expenseAccount.endDate |date}}</dd> - <dd ng-if="editPeriod == true">StartDate : <input type="date" ng-model="expenseAccount.startDate" name="expenseAccount.startDate"></dd> - <dd ng-if="editPeriod == true">EndDate : <input type="date" ng-model="expenseAccount.endDate" name="expenseAccount.endDate"></dd> + </dd> </dl> </div> Modified: trunk/chorem-webmotion/src/main/webapp/js/financial/expenseAccount.js =================================================================== --- trunk/chorem-webmotion/src/main/webapp/js/financial/expenseAccount.js 2014-07-10 12:57:02 UTC (rev 421) +++ trunk/chorem-webmotion/src/main/webapp/js/financial/expenseAccount.js 2014-07-16 14:25:50 UTC (rev 422) @@ -37,23 +37,34 @@ $scope.expenseAccount.expenseAccountEntries = []; } $scope.newExpenseAccountEntry.total = $scope.newExpenseAccountEntry.amount + $scope.newExpenseAccountEntry.VAT; + + if (angular.isDate($scope.newExpenseAccountEntry.emittedDate)) { + $scope.newExpenseAccountEntry.emittedDate = $scope.newExpenseAccountEntry.emittedDate.getTime(); + } + $scope.expenseAccount.expenseAccountEntries.push($scope.newExpenseAccountEntry); $scope.hasChanged = true; $scope.showNewLine = false; delete $scope.newExpenseAccountEntry; - } + }; $scope.saveExpenseAccount = function() { console.log($scope.expenseAccount) url = $scope.baseURL + "financial/expenseAccounts/" + $scope.expenseAccount.id; + if (angular.isDate($scope.expenseAccount.startDate)) { + $scope.expenseAccount.startDate = $scope.expenseAccount.startDate.getTime(); + } + if (angular.isDate($scope.expenseAccount.endDate)) { + $scope.expenseAccount.endDate = $scope.expenseAccount.endDate.getTime(); + } - $resource('url', $scope.expenseAccount, {'update' : {method:'PUT'}}).update(function(result) { + $resource('url', { expenseAccountId : $scope.expenseAccount.id, expenseAccountBean : $scope.expenseAccount }, {'update' : {method:'PUT'}}).update(function(result) { console.log("saved!"); }); - } + }; }); Added: trunk/chorem-webmotion/src/test/java/org/chorem/webmotion/converters/JsonConverterTest.java =================================================================== --- trunk/chorem-webmotion/src/test/java/org/chorem/webmotion/converters/JsonConverterTest.java (rev 0) +++ trunk/chorem-webmotion/src/test/java/org/chorem/webmotion/converters/JsonConverterTest.java 2014-07-16 14:25:50 UTC (rev 422) @@ -0,0 +1,50 @@ +package org.chorem.webmotion.converters; + +import java.util.Date; +import java.util.Set; + +import org.chorem.webmotion.bean.financial.ExpenseAccountBean; +import org.chorem.webmotion.bean.financial.ExpenseAccountEntryBean; +import org.junit.Assert; +import org.junit.Test; +import org.nuiton.util.DateUtil; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class JsonConverterTest { + + @Test + public void testConvertExpenseAccountBeanFromJson() throws Exception { + + String employeeName = "Lucius Fox (WayneCorp)"; + String employeeId = "f44720a5-f003-4b3f-bfb9-a9189d0ab7d6"; + Date startDate = DateUtil.createDate(01, 07, 2014); + Date endDate = DateUtil.createDate(31, 07, 2014); + Date emittedDate = DateUtil.createDate(05, 07, 2014); + + String json = "{" + + "\"id\":\"f44720a5-f003-4b3f-bfb9-a9189d0ab7d6\"" + + ",\"employeeName\":\"" + employeeName + "\"" + + ",\"employeeId\":\"" + employeeId + "\"" + + ",\"startDate\":\"" + startDate.getTime() + "\"" + + ",\"endDate\":\"" + endDate.getTime() + "\"" + + ",\"expenseAccountEntries\":[{\"justificationNumber\":\"Depl-0507\",\"emittedDate\":\"" + emittedDate.getTime() + "\",\"project\":\"\",\"description\":\"Deplacement\",\"category\":\"\",\"amount\":16,\"VAT\":4,\"total\":20,\"categoryName\":\"Train Hotel Repas Km\",\"categoryId\":\"d6cd6f26-44cb-4a45-a1cf-f41c6dd6fe7f\"}]" + + "}"; + JsonConverter<ExpenseAccountBean> expenseAccountJsonConverter = JsonConverter.newConverter(ExpenseAccountBean.class); + ExpenseAccountBean expenseAccount = expenseAccountJsonConverter.convert(ExpenseAccountBean.class, json); + Assert.assertNotNull(expenseAccount); + Assert.assertNotNull(expenseAccount.getId()); + Assert.assertEquals(employeeId, expenseAccount.getEmployeeId()); + Assert.assertEquals(employeeName, expenseAccount.getEmployeeName()); + Assert.assertEquals(startDate.getTime(), expenseAccount.getStartDate().getTime()); + Assert.assertEquals(endDate.getTime(), expenseAccount.getEndDate().getTime()); + Set<ExpenseAccountEntryBean> expenseAccountEntries = expenseAccount.getExpenseAccountEntries(); + Assert.assertNotNull(expenseAccountEntries); + Assert.assertEquals(1, expenseAccountEntries.size()); + ExpenseAccountEntryBean expenseAccountEntryBean = expenseAccountEntries.iterator().next(); + Assert.assertEquals(emittedDate.getTime(), expenseAccountEntryBean.getEmittedDate().getTime()); + + } + +} Added: trunk/chorem-webmotion/src/test/resources/log4j.properties =================================================================== --- trunk/chorem-webmotion/src/test/resources/log4j.properties (rev 0) +++ trunk/chorem-webmotion/src/test/resources/log4j.properties 2014-07-16 14:25:50 UTC (rev 422) @@ -0,0 +1,36 @@ +### +# #%L +# Chorem webmotion +# $Id: log4j.properties 410 2014-04-09 14:29:44Z ymartel $ +# $HeadURL: https://svn.chorem.org/chorem/trunk/chorem-webmotion/src/main/resources/log4... $ +# %% +# Copyright (C) 2011 - 2012 CodeLutin +# %% +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# #L% +### +# Global logging configuration +log4j.rootLogger=INFO, stdout + +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d %5p [%t] (%F:%L) %M - %m%n + +# package level +log4j.logger.org.chorem=DEBUG +log4j.logger.org.nuiton=INFO +log4j.logger.org.debux=ERROR +log4j.logger.org.apache=ERROR +#log4j.logger.org.nuiton.wikitty.storage.solr.SolrUtil=DEBUG