Author: bpoussin Date: 2013-02-21 20:19:48 +0100 (Thu, 21 Feb 2013) New Revision: 309 Url: http://chorem.org/projects/chorem/repository/revisions/309 Log: budget, annualProfit fonctionne ajout d'un rapport pour aider a la declaration de la TVA mensuel mise a jour des menus Added: trunk/chorem-entities/src/main/java/org/chorem/ChoremUtil.java trunk/chorem-entities/src/test/java/org/chorem/ChoremUtilTest.java trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardVAT.jsp Modified: trunk/chorem-entities/src/main/java/org/chorem/ChoremQueryMaker.java trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/DashboardAction.java trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/GenericAction.java trunk/chorem-webmotion/src/main/resources/mapping trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardAnnualProfit.jsp trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/report.jsp trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/view.jsp trunk/pom.xml Modified: trunk/chorem-entities/src/main/java/org/chorem/ChoremQueryMaker.java =================================================================== --- trunk/chorem-entities/src/main/java/org/chorem/ChoremQueryMaker.java 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-entities/src/main/java/org/chorem/ChoremQueryMaker.java 2013-02-21 19:19:48 UTC (rev 309) @@ -84,4 +84,36 @@ return this; } + // + // Des methodes utilisables en function dans les select + // + + /** + * Applique la vat sur le montant et retourne le total. + * ex: amount = 100 et vat = 19.6 le resultat sera 119.6 + * + * + * @param amount + * @param vat + * @return + */ + static public double amountTTC(double amount, double vat) { + double result = amount * (1+vat/100); + return result; + } + + /** + * Calcul la TVA du par rapport au montant. + * ex: amount = 100 et vat = 19.6 le resultat sera 19.6 + * + * + * @param amount + * @param vat + * @return + */ + static public double amountVAT(double amount, double vat) { + double result = amount * vat / 100; + return result; + } + } Added: trunk/chorem-entities/src/main/java/org/chorem/ChoremUtil.java =================================================================== --- trunk/chorem-entities/src/main/java/org/chorem/ChoremUtil.java (rev 0) +++ trunk/chorem-entities/src/main/java/org/chorem/ChoremUtil.java 2013-02-21 19:19:48 UTC (rev 309) @@ -0,0 +1,48 @@ +package org.chorem; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class ChoremUtil { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(ChoremUtil.class); + + final static public String DEFAULT_SEPARATOR_LIST = ","; + + /** + * Transforme un tableau en une liste, si un element du tableau utilise + * le separateur alors, il est lui meme decoupe pour que chaque element + * finisse dans la liste retournee + * + * @param separator le separateur a utiliser (si null, alors DEFAULT_SEPARATOR_LIST est utilise) + * @param s + * @return + */ + static public List<String> asList(String separator, String ... array) { + if (separator == null) { + separator = DEFAULT_SEPARATOR_LIST; + } + List<String> result = new ArrayList<String>(); + for (String s : array) { + String[] tmp = StringUtils.split(s, separator); + for (String t : tmp) { + result.add(t); + } + } + return result; + } +} Added: trunk/chorem-entities/src/test/java/org/chorem/ChoremUtilTest.java =================================================================== --- trunk/chorem-entities/src/test/java/org/chorem/ChoremUtilTest.java (rev 0) +++ trunk/chorem-entities/src/test/java/org/chorem/ChoremUtilTest.java 2013-02-21 19:19:48 UTC (rev 309) @@ -0,0 +1,30 @@ +package org.chorem; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Test; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class ChoremUtilTest { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(ChoremUtilTest.class); + + @Test + public void testAsList() { + String ext = "Company,Employee,Person"; + String[] tab = new String[]{"Company","Employee,Person"}; + + Assert.assertEquals(ChoremUtil.asList(null, ext), ChoremUtil.asList(null, tab)); + } + +} Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/DashboardAction.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/DashboardAction.java 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/DashboardAction.java 2013-02-21 19:19:48 UTC (rev 309) @@ -23,10 +23,12 @@ package org.chorem.webmotion.actions; +import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -67,7 +69,6 @@ import org.nuiton.wikitty.query.WikittyQueryMaker; import org.nuiton.wikitty.query.WikittyQueryResult; import org.nuiton.wikitty.query.WikittyQueryResultTreeNode; -import org.nuiton.wikitty.query.conditions.Aggregate; /** * @@ -149,68 +150,168 @@ // //////////////////////////////////////////////////////////////////////////// - protected WikittyQuery[] getDebtIncomeQuery(Date first, Date last, String companyId) { + /** + * Cette requete comporte un select retournant un nombre nomme: + * <li>debts: le montant TTC + * + * Le calcul se fait sur toutes les FinancialTransaction non annulee + * + * @param first + * @param last + * @param companyId l'identifiant de la company dont elle ou un de ses employers + * doit etre en Payer + * @return + */ + protected WikittyQuery getDebtQuery(Date first, Date last, String companyId) { // toutes les depenses depuis le debut de l'annee WikittyQuery debtQuery = new ChoremQueryMaker() - .select().sum(Invoice.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .select() + .sum((String)null, "debts") + .function("#amountTTC") + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .where() .and() - .exteq(Invoice.EXT_FINANCIALTRANSACTION) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) .not().eq(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED.name()) - .bw(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, first, last) - .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYER) + .bw(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, first, last) + .containsOne(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYER) .select(Element.ID).filterOnCompanyOrEmployee(companyId) .end().setLimit(WikittyQuery.MAX); + return debtQuery; + } + + /** + * Cette requete comporte un select retournant deux nombre nomme: + * <li>incomes: le montant total HT des factures + * <li>incomesTTC: le montant total TTC des factures + * + * Le calcul se fait uniquement sur les Invoices + * + * @param first + * @param last + * @param companyId l'identifiant de la company dont elle ou un de ses employers + * doit etre en Beneficiary + * @return + */ + protected WikittyQuery getIncomeInvoiceQuery(Date first, Date last, String companyId) { // toutes les factures emises depuis le debut de l'annee WikittyQuery incomeQuery = new ChoremQueryMaker() - .select().sum(Invoice.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .select() + .sum(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT, "incomes") + .sum((String)null, "incomesTTC") + .function("#amountTTC") + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .where() .and() - .exteq(Invoice.EXT_FINANCIALTRANSACTION) + .exteq(Invoice.EXT_INVOICE) .not().eq(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED.name()) - .bw(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, first, last) - .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) + .bw(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, first, last) + .containsOne(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) .select(Element.ID).filterOnCompanyOrEmployee(companyId) .end().setLimit(WikittyQuery.MAX); - - WikittyQuery[] result = new WikittyQuery[]{ - debtQuery, incomeQuery - }; - return result; + + return incomeQuery; } /** + * Cette requete comporte un select retournant deux nombre nomme: + * <li>extraIncomes: le montant total HT des factures + * <li>extraIncomesTTC: le montant total TTC des factures + * + * Le calcul se fait sur toutes les FinancialTransaction qui ne sont pas aussi Invoice + * + * @param first + * @param last + * @param companyId l'identifiant de la company dont elle ou un de ses employers + * doit etre en Beneficiary + * @return + */ + protected WikittyQuery getExtraIncomeQuery(Date first, Date last, String companyId) { + // toutes les factures emises depuis le debut de l'annee + WikittyQuery incomeQuery = new ChoremQueryMaker() + .select() + .sum(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT, "extraIncomes") + .sum((String)null, "extraIncomesTTC") + .function("#amountTTC") + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .where() + .and() + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) + .extne(Invoice.EXT_INVOICE) + .bw(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, first, last) + .containsOne(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) + .select(Element.ID).filterOnCompanyOrEmployee(companyId) + .end().setLimit(WikittyQuery.MAX); + + return incomeQuery; + } + + /** + * Retourne le total des entree et sortie entre deux dates, les valeurs retournees sont: + * + * <li>debts: le montant TTC + * <li>incomes: le montant total HT des factures + * <li>incomesTTC: le montant total TTC des factures + * <li>extraIncomes: le montant total HT des revenus hors facture + * <li>extraIncomesTTC: le montant total TTC des revenus hors factures + * + * @param client + * @param first + * @param last + * @param companyId + * @return + */ + protected Map<String, Double> getDebtIncome(ChoremClient client, + Date first, Date last, String companyId) { + List<WikittyQuery> queries = new ArrayList<WikittyQuery>(3); + queries.add(getDebtQuery(first, last, companyId)); + queries.add(getIncomeInvoiceQuery(first, last, companyId)); + queries.add(getExtraIncomeQuery(first, last, companyId)); + + List<Map<String, Double>> values = client.findByQueryAsMap( + Double.class, queries); + Map<String, Double> aggregate = new HashMap<String, Double>(); + for (Map<String, Double> m : values) { + aggregate.putAll(m); + } + return aggregate; + } + + /** * Dashbord qui indique pour toutes les annees du systeme le CA et les depenses * @param client * @return */ public Render annualProfit(ChoremClient client) { - Map<Date, Double[]> result = new TreeMap<Date, Double[]>(); String companyId = client.getConfiguration().getDefaultCompany(); // La premiere annee - WikittyQuery firstDateQuery = new WikittyQueryMaker() - .select().min(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE) - .exteq(Invoice.EXT_INVOICE) + WikittyQuery dateQuery = new WikittyQueryMaker() + .select() + .min(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, "firstDate") + .max(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, "lastDate") + .where() + .exteq(Invoice.EXT_INVOICE) .end().setLimit(WikittyQuery.MAX); - // La derniere annee - WikittyQuery lastDateQuery = new WikittyQueryMaker() - .select().max(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE) - .exteq(Invoice.EXT_INVOICE) - .end().setLimit(WikittyQuery.MAX); - Date[] dates = client.findByQuery(Date.class, firstDateQuery, lastDateQuery); - Date firstDay = DateUtil.setFirstDayOfYear(dates[0]); - Date lastDay = DateUtil.setLastDayOfYear(dates[1]); - log.debug(String.format("first date: %s last date: %s", dates[0], dates[1])); - + Map<String, Date> dates = client.findByQueryAsMap(Date.class, dateQuery); + Date firstDay = DateUtil.setFirstDayOfYear(dates.get("firstDate")); + Date lastDay = DateUtil.setLastDayOfYear(dates.get("lastDate")); + + log.debug(String.format("date: %s", dates)); + + Map<Date, Map<String, Double>> result = new TreeMap<Date, Map<String, Double>>(); + Date currentFirst = firstDay; Date currentLast = DateUtil.setLastDayOfYear(firstDay); while (currentLast.compareTo(lastDay) <= 0) { - WikittyQuery[] annualDebtIncomeQuery = - getDebtIncomeQuery(currentFirst, currentLast, companyId); - Double[] values = client.findByQuery(Double.class, - annualDebtIncomeQuery[0], annualDebtIncomeQuery[1]); + Map<String, Double> values = getDebtIncome(client, + currentFirst, currentLast, companyId); result.put(currentFirst, values); currentFirst = DateUtils.addYears(currentFirst, 1); currentLast = DateUtils.addYears(currentLast, 1); @@ -234,14 +335,20 @@ String companyId = client.getConfiguration().getDefaultCompany(); // toutes les depenses depuis le debut de l'annee - WikittyQuery[] annualDebtIncomeQuery = getDebtIncomeQuery(firstDayYear, now, companyId); - WikittyQuery[] pastAnnualDebtIncomeQuery = getDebtIncomeQuery(lastYearFirstDay, lastYearNow, companyId); + Map<String, Double> annualDebtIncome = getDebtIncome(client, + firstDayYear, now, companyId); + Map<String, Double> pastAnnualDebtIncome = getDebtIncome(client, + lastYearFirstDay, lastYearNow, companyId); +// WikittyQuery[] annualDebtIncomeQuery = getDebtIncomeQuery(firstDayYear, now, companyId); +// WikittyQuery[] pastAnnualDebtIncomeQuery = getDebtIncomeQuery(lastYearFirstDay, lastYearNow, companyId); + // les factures que notre societe doit payer au plus tard dans 7 jours WikittyQuery invoiceDebtQuery = new ChoremQueryMaker() .select().sum(Invoice.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) .and() - .exteq(Invoice.EXT_INVOICE) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) + .not().eq(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED.name()) .lt(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EXPECTEDDATE, inOneWeek) .isNull(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYER) @@ -252,14 +359,15 @@ WikittyQuery invoiceIncomeQuery = new ChoremQueryMaker() .select().sum(Invoice.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) .and() - .exteq(Invoice.EXT_INVOICE) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) + .not().eq(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED.name()) .lt(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EXPECTEDDATE, now) .isNull(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) .select(Element.ID).filterOnCompanyOrEmployee(companyId) .end().setLimit(WikittyQuery.MAX); - // les contacts qui doivnet etre pris dans les 7 prochains jours + // les contacts qui doivent etre pris dans les 7 prochains jours WikittyQuery touchQuery = new WikittyQueryMaker().and() .exteq(Touch.EXT_TOUCH) .lt(Interval.FQ_FIELD_INTERVAL_BEGINDATE, inOneWeek) @@ -268,9 +376,7 @@ WikittyQueryResult<Double>[] invoices = client.findAllByQuery(Double.class, - invoiceDebtQuery, invoiceIncomeQuery, - annualDebtIncomeQuery[0], annualDebtIncomeQuery[1], - pastAnnualDebtIncomeQuery[0], pastAnnualDebtIncomeQuery[1]); + invoiceDebtQuery, invoiceIncomeQuery); WikittyQueryResult<String> touchs = client.findAllByQuery(touchQuery); @@ -286,12 +392,12 @@ double invoiceIncome = invoices[1].peek(); // montant total de toutes les factures - double annualDebt = invoices[2].peek(); - double annualIncome = invoices[3].peek(); + double annualDebt = annualDebtIncome.get("debts"); + double annualIncome = annualDebtIncome.get("incomes"); // montant total de toutes les factures - double lastYearAnnualDebt = invoices[4].peek(); - double lastYearAnnualIncome = invoices[5].peek(); + double lastYearAnnualDebt = pastAnnualDebtIncome.get("debts"); + double lastYearAnnualIncome = pastAnnualDebtIncome.get("incomes"); int touchNb = touchs.getTotalResult(); @@ -682,45 +788,58 @@ // La somme des factures que la company doit payer jusqu'a la date demandee WikittyQuery debt = new ChoremQueryMaker() - .select().sum(Invoice.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .select() + .sum((String)null, "debts") + .function("#amountTTC") + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .where() .and() - .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYER) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) + .containsOne(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYER) .select(Element.ID).filterOnCompanyOrEmployee(companyId) .close() .not().eq(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED) .or() .and() - .isNotNull(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) - .lt(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE, start) + .isNotNull(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) + .lt(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE, start) .close() .and() - .isNull(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) - .lt(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EXPECTEDDATE, start) + .isNull(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) + .lt(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_EXPECTEDDATE, start) .end() .setLimit(WikittyQuery.MAX); // La somme des factures que la company doit percevoir jusqu'a la date demandee WikittyQuery income = new ChoremQueryMaker() - .select().sum(Invoice.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .select() + .sum((String)null, "incomes") + .function("#amountTTC") + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .where() .and() - .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) + .containsOne(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) .select(Element.ID).filterOnCompanyOrEmployee(companyId) .close() .not().eq(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED) .or() .and() - .isNotNull(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) - .lt(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE, start) + .isNotNull(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) + .lt(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE, start) .close() .and() - .isNull(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) - .lt(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EXPECTEDDATE, start) + .isNull(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE) + .lt(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_EXPECTEDDATE, start) .end() .setLimit(WikittyQuery.MAX); // La liste des factures entre les deux dates que l'on doit payer WikittyQuery invoiceDebt = new ChoremQueryMaker().and() .parse(query) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYER) .select(Element.ID).filterOnCompanyOrEmployee(companyId) .close() @@ -739,6 +858,7 @@ // La liste des factures entre les deux dates que l'on doit payer WikittyQuery invoiceIncome = new ChoremQueryMaker().and() .parse(query) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) .select(Element.ID).filterOnCompanyOrEmployee(companyId) .close() @@ -870,16 +990,19 @@ String date = DateFormatUtils.format(d, budgetDateFormat); Category c = invoice.getCategory(false); double amount = invoice.getAmount(); + double vat = invoice.getVAT(); - addAmount(date, c, amount); + double ttc = ChoremQueryMaker.amountTTC(amount, vat); + + addAmount(date, c, ttc); addInvoice(date, c, invoice); if (debt) { - addDebt(date, amount); - addTotal(date, -amount); + addDebt(date, ttc); + addTotal(date, -ttc); } else { - addIncome(date, amount); - addTotal(date, amount); + addIncome(date, ttc); + addTotal(date, ttc); } } @@ -957,6 +1080,142 @@ } } + + /** + * Retourne le total de la tva entree et sortie entre deux dates, les valeurs retournees sont: + * + * <li>(Double)vatDebt: le montant de la tva sur les depenses + * <li>(Double)vatIncome: le montant de la tva sur les entrees + * <li>(String)vatDebtQuery: la query permettant de retrouve les factures utilise + * <li>(String)vatIncomeQuery: la query permettant de retrouve les factures utilise + * + * @param client + * @param start + * @param end + * @param companyId + * @return + */ + protected Map<String, Object> getVAT(ChoremClient client, + Date start, Date end, String query, String companyId) { + + // La liste des factures entre les deux dates que l'on doit payer + WikittyQuery vatDebtQuery = new ChoremQueryMaker() + .and() + .parse(query) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) + .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYER) + .select(Element.ID).filterOnCompanyOrEmployee(companyId) + .close() + .ne(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED) + .isNotNull(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .ne(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT, 0) + .bw(Invoice.FQ_FIELD_FINANCIALTRANSACTION_EMITTEDDATE, start, end) + .end() + .setLimit(WikittyQuery.MAX); + + WikittyQuery vatDebt = new ChoremQueryMaker() + .select() + .sum((String)null, "vatDebt") + .function("#amountVAT") + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .where() + .condition(vatDebtQuery.getCondition()) + .end() + .setLimit(WikittyQuery.MAX); + + // La liste des factures entre les deux dates que l'on doit payer + WikittyQuery vatIncomeQuery = new ChoremQueryMaker() + .and() + .parse(query) + .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION) + .containsOne(Invoice.FQ_FIELD_FINANCIALTRANSACTION_BENEFICIARY) + .select(Element.ID).filterOnCompanyOrEmployee(companyId) + .close() + .ne(Invoice.FQ_FIELD_INVOICE_STATUS, InvoiceStatus.CANCELED) + .isNotNull(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .ne(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT, 0) + .bw(Invoice.FQ_FIELD_FINANCIALTRANSACTION_PAYMENTDATE, start, end) + .end() + .setLimit(WikittyQuery.MAX); + + // La liste des factures entre les deux dates que l'on doit payer + WikittyQuery vatIncome = new ChoremQueryMaker() + .select() + .sum((String)null, "vatIncome") + .function("#amountVAT") + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_AMOUNT) + .fieldValue(FinancialTransaction.FQ_FIELD_FINANCIALTRANSACTION_VAT) + .where() + .condition(vatIncomeQuery.getCondition()) + .end() + .setLimit(WikittyQuery.MAX); + + + Double[] values = client.findByQuery(Double.class, vatDebt, vatIncome); + Map<String, Object> aggregate = new HashMap<String, Object>(); + aggregate.put("vatDebt", values[0]); + aggregate.put("vatIncome", values[1]); + + aggregate.put("vatDebtQuery", vatDebtQuery.getCondition().toString()); + aggregate.put("vatIncomeQuery", vatIncomeQuery.getCondition().toString()); + + return aggregate; + } + + /** + * Prévisionnel entre deux dates en fonction des factures + */ + public Render vat(ChoremClient client, Date start, Date end, String query) { + if (log.isDebugEnabled()) { + log.debug(String.format( + "vat for period '%s' to '%s' with filter '%s'", + start, end, query)); + } + String companyId = client.getConfiguration().getDefaultCompany(); + + if (StringUtils.isBlank(companyId)) { + getContext().addInfoMessage("message", "Vous devez définir une société par défaut"); + return renderURL("/admin/variables"); + } + + if (start == null) { + start = new Date(); + start = DateUtils.addMonths(start, -6); + } + + if (end == null) { + end = DateUtils.addMonths(start, 6); + } + + start = DateUtil.setFirstDayOfMonth(start); + end = DateUtil.setLastDayOfMonth(end); + + start = DateUtil.setMinTimeOfDay(start); + end = DateUtil.setMaxTimeOfDay(end); + + + Map<Date, Map<String, Object>> data = new LinkedHashMap<Date, Map<String, Object>>(); + + Date currentFirst = start; + Date currentLast = DateUtil.setLastDayOfMonth(start); + while (currentLast.compareTo(end) <= 0) { + Map<String, Object> vat = getVAT(client, currentFirst, currentLast, query, companyId); + data.put(currentFirst, vat); + currentFirst = DateUtils.addMonths(currentFirst, 1); + currentLast = DateUtils.addMonths(currentLast, 1); + } + + if (log.isDebugEnabled()) { + log.debug(String.format( + "vat for period '%s' to '%s' with filter '%s = %s'", + start, end, query, data)); + } + + return renderView("dashboardVAT.jsp", "data", data); + } + + //////////////////////////////////////////////////////////////////////////// // // H R Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/GenericAction.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/GenericAction.java 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/GenericAction.java 2013-02-21 19:19:48 UTC (rev 309) @@ -62,6 +62,8 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; +import org.chorem.ChoremUtil; +import org.nuiton.wikitty.WikittyUtil; /** * @@ -161,7 +163,7 @@ // S'il y a des extensions on force la requete sur ces types d'extension if (extension != null) { maker = new WikittyQueryMaker().and() - .extContainsOne(Arrays.asList(extension)); + .extContainsOne(ChoremUtil.asList(null, extension)); } else { maker = new WikittyQueryMaker(); } @@ -199,7 +201,7 @@ Set<String> exts = null; if (extension != null && extension.length > 0) { - exts = new HashSet<String>(Arrays.asList(extension)); + exts = new HashSet<String>(ChoremUtil.asList(null, extension)); } Set<String> extExcluded = new HashSet<String>(client.getConfig().getOptionAsList( @@ -313,7 +315,7 @@ } } else { // utilisation des extensions demande en parametre - extNames = Arrays.asList(extension); + extNames = ChoremUtil.asList(null, extension); expliciteExtension = true; } @@ -416,7 +418,7 @@ exts.addAll(w.getExtensions()); } else { // Display the extensions and required ones for them - List<String> extensionNames = Arrays.asList(extension); + List<String> extensionNames = ChoremUtil.asList(null, extension); List<WikittyExtension> wikittyExtensions = client.restoreExtensionAndDependenciesLastVesion(extensionNames); exts.addAll(wikittyExtensions); } @@ -447,7 +449,8 @@ return renderView("view.jsp", "wikitty", w, "extensions", exts, "viewActions", viewActions); } - public Render edit(ChoremClient client, String id, String[] extension, Call call) { + public Render edit(ChoremClient client, String id, Boolean copy, + String[] extension, Call call) { log.debug("edit: " + id); // on preload rien, le preload sera fait a la fin Wikitty w = client.restore(id, ""); @@ -455,6 +458,11 @@ // si on ne retrouve pas l'objet demande, on en edit un nouveau if (w == null) { w = new WikittyImpl(); + } else if (copy != null && copy) { + // on copie le wikitty trouve pour qu'a la sauvegarde ce soit un nouveau qui soit creer + WikittyImpl newW = new WikittyImpl(); + newW.replaceWith(w, true); + w = newW; } LinkedHashSet<WikittyExtension> exts = new LinkedHashSet<WikittyExtension>(); @@ -464,7 +472,7 @@ exts.addAll(w.getExtensions()); } else { // Be sure that the wikitty has good extension if wanted and their requirements - List<String> extensionNames = Arrays.asList(extension); + List<String> extensionNames = ChoremUtil.asList(null, extension); List<WikittyExtension> newExts = client.restoreExtensionAndDependenciesLastVesion(extensionNames); w.addExtension(newExts); @@ -495,13 +503,12 @@ if (extension != null) { // Be sure that the wikitty has good extension if wanted and their requirements - List<String> extensionNames = Arrays.asList(extension); + List<String> extensionNames = ChoremUtil.asList(null, extension); newExts = client.restoreExtensionAndDependenciesLastVesion(extensionNames); exts.addAll(newExts); } - String[] idArrays = StringUtils.split(ids, ","); - List<Wikitty> ws = client.restore(Arrays.asList(idArrays)); + List<Wikitty> ws = client.restore(ChoremUtil.asList(null, ids)); ArrayList<Integer> newW = new ArrayList<Integer>(); int index = 0; @@ -575,7 +582,7 @@ w = new WikittyImpl(); } List<WikittyExtension> exts = - client.restoreExtensionAndDependenciesLastVesion(Arrays.asList(extension)); + client.restoreExtensionAndDependenciesLastVesion(ChoremUtil.asList(null, extension)); w.addExtension(exts); Map<String, Object> params = call.getExtractParameters(); String error = setWikittyField(w, "", params); @@ -601,7 +608,7 @@ String[] extension = (String[]) params.get(id + ".extension"); List<WikittyExtension> exts = - client.restoreExtensionAndDependenciesLastVesion(Arrays.asList(extension)); + client.restoreExtensionAndDependenciesLastVesion(ChoremUtil.asList(null, extension)); w.addExtension(exts); String error = setWikittyField(w, id + ".", params); Modified: trunk/chorem-webmotion/src/main/resources/mapping =================================================================== --- trunk/chorem-webmotion/src/main/resources/mapping 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-webmotion/src/main/resources/mapping 2013-02-21 19:19:48 UTC (rev 309) @@ -31,6 +31,7 @@ * /wikitty/searchRelated?id={query} action:GenericAction.search * /wikitty/view/{id} action:GenericAction.view * /wikitty/edit/{id} action:GenericAction.edit +* /wikitty/copy/{id} action:GenericAction.edit copy=true * /wikitty/editMulti/{ids} action:GenericAction.editMulti * /wikitty/delete/{id} action:GenericAction.delete * /wikitty/save action:GenericAction.save Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardAnnualProfit.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardAnnualProfit.jsp 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardAnnualProfit.jsp 2013-02-21 19:19:48 UTC (rev 309) @@ -31,16 +31,22 @@ <th>Année</th> <th>CA HT</th> <th>CA TTC</th> + <th>Autre revenu HT</th> + <th>Autre revenu TTC</th> <th>Dépense</th> + <th>CA TTC - Dépense</th> <th>Bénéfice/perte</th> </tr> <c:forEach var="q" items="${annualProfit.keySet()}"> <tr> <th><f:formatDate pattern="yyyy" value="${q}"/></th> - <td><f:formatNumber type="currency" value="${annualProfit.get(q)[1]}"/></td> - <td><f:formatNumber type="currency" value="${annualProfit.get(q)[1]*1.196}"/></td> - <td><f:formatNumber type="currency" value="${annualProfit.get(q)[0]}"/></td> - <td><f:formatNumber type="currency" value="${annualProfit.get(q)[1]*1.196 - annualProfit.get(q)[0]}"/></td> + <td><f:formatNumber type="currency" value="${annualProfit.get(q).get('incomes')}"/></td> + <td><f:formatNumber type="currency" value="${annualProfit.get(q).get('incomesTTC')}"/></td> + <td><f:formatNumber type="currency" value="${annualProfit.get(q).get('extraIncomes')}"/></td> + <td><f:formatNumber type="currency" value="${annualProfit.get(q).get('extraIncomesTTC')}"/></td> + <td><f:formatNumber type="currency" value="${annualProfit.get(q).get('debts')}"/></td> + <td><f:formatNumber type="currency" value="${annualProfit.get(q).get('incomesTTC') - annualProfit.get(q).get('debts')}"/></td> + <td><f:formatNumber type="currency" value="${annualProfit.get(q).get('incomesTTC') + annualProfit.get(q).get('extraIncomesTTC') - annualProfit.get(q).get('debts')}"/></td> </tr> </c:forEach> </table> Copied: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardVAT.jsp (from rev 307, trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardBudget.jsp) =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardVAT.jsp (rev 0) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardVAT.jsp 2013-02-21 19:19:48 UTC (rev 309) @@ -0,0 +1,67 @@ +<%-- + #%L + Chorem webmotion + $Id:$ + $HeadURL:$ + %% + 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% + --%> +<%@page contentType="text/html" pageEncoding="UTF-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="f" %> +<%@ taglib uri="/WEB-INF/wikitty.tld" prefix="w"%> + +<h1>Budget</h1> + +<table class="table table-striped table-bordered table-condensed"> + <thead> + <tr> + <th>Mois</th> + <c:forEach var="d" items="${data.keySet()}"> + <th><f:formatDate pattern="MM/yyyy" value="${d}"/></th> + </c:forEach> + </tr> + </thead> + <tbody> + <tr> + <th><span>TVA payer</span></th> + <c:forEach var="d" items="${data.values()}"> + <td class="currency"> + <a href='<c:url value="/wikitty/search?query=${d.get('vatDebtQuery')}"/>'> + <span><f:formatNumber type="currency" value='${d.get("vatDebt")}'/></span> + </a> + </td> + </c:forEach> + </tr> + <tr> + <th><span>TVA encaissé</span></th> + <c:forEach var="d" items="${data.values()}"> + <td class="currency"> + <a href='<c:url value="/wikitty/search?query=${d.get('vatIncomeQuery')}"/>'> + <span><f:formatNumber type="currency" value='${d.get("vatIncome")}'/></span> + </a> + </td> + </c:forEach> + </tr> + <tr> + <th><span>TVA à déclarer</span></th> + <c:forEach var="d" items="${data.values()}"> + <td class="currency"><span><f:formatNumber type="currency" value='${d.get("vatIncome") - d.get("vatDebt")}'/></span></td> + </c:forEach> + </tr> + </tbody> +</table> Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp 2013-02-21 19:19:48 UTC (rev 309) @@ -138,6 +138,10 @@ <li><a href="<c:url value="/wikitty/Quotation/search"/>"><i class="icon-th-list icon-black"></i> All quotations</a></li> <li><a href="<c:url value="/wikitty/Quotation/edit/new"/>"><i class="icon-plus icon-black"></i> Add quotation</a></li> <li class="divider"></li> + <li>FinancialTransaction</li> + <li><a href="<c:url value="/wikitty/FinancialTransaction/search"/>"><i class="icon-th-list icon-black"></i> All financial transactions</a></li> + <li><a href="<c:url value="/wikitty/FinancialTransaction/edit/new"/>"><i class="icon-plus icon-black"></i> Add financial transactions</a></li> + <li class="divider"></li> <li>Invoice</li> <li><a href="<c:url value="/wikitty/Invoice/search"/>"><i class="icon-th-list icon-black"></i> All invoices</a></li> <li><a href="<c:url value="/wikitty/Invoice/edit/new"/>"><i class="icon-plus icon-black"></i> Add invoice</a></li> @@ -147,6 +151,7 @@ <li><a href="<c:url value="/wikitty/Category/edit/new"/>"><i class="icon-plus icon-black"></i> Add category</a></li> <li class="divider"></li> <li>Report</li> + <li><a href="<c:url value="/report?report=vat"/>">TVA mensuel</a></li> <li><a href="<c:url value="/report?report=invoiceDebt"/>">Debt</a></li> <li><a href="<c:url value="/report?report=invoiceIncome"/>">Income</a></li> <li><a href="<c:url value="/report?report=profitability"/>">Profitability</a></li> Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/report.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/report.jsp 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/report.jsp 2013-02-21 19:19:48 UTC (rev 309) @@ -22,6 +22,7 @@ --%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <form class="well form-inline"> <input type="hidden" name="report" value="${report}"/> @@ -31,35 +32,7 @@ <input type="submit" class="btn"/> </form> - <%-- Rapport de projet --%> - <c:if test="${report == null || report == '' || report.contains('quotation')}"> - <jsp:include page="/fragment/dashboard/quotation"/> - </c:if> - <c:if test="${report == null || report == '' || report.contains('projectOpen')}"> - <jsp:include page="/fragment/dashboard/projectOpen"/> - </c:if> - <c:if test="${report == null || report == '' || report.contains('projectClosed')}"> - <jsp:include page="/fragment/dashboard/projectClosed"/> - </c:if> - - <%-- Rapport financier --%> - <c:if test="${report == null || report == '' || report.contains('invoiceDebt')}"> - <jsp:include page="/fragment/dashboard/invoiceDebt"/> - </c:if> - <c:if test="${report == null || report == '' || report.contains('invoiceIncome')}"> - <jsp:include page="/fragment/dashboard/invoiceIncome"/> - </c:if> - <c:if test="${report == null || report == '' || report.contains('profitability')}"> - <jsp:include page="/fragment/dashboard/profitability"/> - </c:if> - <c:if test="${report == null || report == '' || report.contains('budget')}"> - <jsp:include page="/fragment/dashboard/budget"/> - </c:if> - <c:if test="${report == null || report == '' || report.contains('annualProfit')}"> - <jsp:include page="/fragment/dashboard/annualProfit"/> - </c:if> - - <%-- Tableau des congés --%> - <c:if test="${report == null || report == '' || report.contains('requestVacation')}"> - <jsp:include page="/fragment/dashboardHR/requestVacation"/> - </c:if> + <%-- affichage de tous les rapports demandes --%> + <c:forEach var="r" items="${fn:split(report, ',')}"> + <jsp:include page="/fragment/dashboard/${r}"/> + </c:forEach> Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/view.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/view.jsp 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/view.jsp 2013-02-21 19:19:48 UTC (rev 309) @@ -28,6 +28,7 @@ <c:if test="${not empty wikitty}"> <a class="btn btn-success" href="<c:url value="/wikitty/view/${wikitty.id}"/>"><i class="icon-list icon-white"></i> View all extension</a> <a class="btn btn-success" href="<c:url value="/wikitty/edit/${wikitty.id}"/>"><i class="icon-pencil icon-white"></i> Edit object</a> + <a class="btn btn-success" href="<c:url value="/wikitty/copy/${wikitty.id}"/>"><i class="icon-random icon-white"></i> Copy object</a> <a class="btn btn-danger" href="<c:url value="/wikitty/delete/${wikitty.id}?wmDecoratorNo=true"/>"><i class="icon-trash icon-white"></i> Delete object</a> </c:if> </p> Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2013-02-20 11:45:41 UTC (rev 308) +++ trunk/pom.xml 2013-02-21 19:19:48 UTC (rev 309) @@ -95,7 +95,7 @@ <opencsvVersion>2.3</opencsvVersion> <processPluginVersion>1.1</processPluginVersion> <eugenePluginVersion>2.6</eugenePluginVersion> - <nuitonUtilsVersion>2.6.5</nuitonUtilsVersion> + <nuitonUtilsVersion>2.6.9-SNAPSHOT</nuitonUtilsVersion> <nuitonWebVersion>1.7</nuitonWebVersion> <nuitonI18nVersion>2.3.1</nuitonI18nVersion> <wikittyVersion>3.9-SNAPSHOT</wikittyVersion>