// // Copyright (c) 2011 Linkeos. // // This file is part of Elveos.org. // Elveos.org is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // Elveos.org 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 General Public License along // with Elveos.org. If not, see http://www.gnu.org/licenses/. // package com.bloatit.web.components; import static com.bloatit.framework.webprocessor.context.Context.tr; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.bloatit.data.DaoBankTransaction.State; import com.bloatit.data.DaoFeature.FeatureState; import com.bloatit.data.DaoMoneyWithdrawal; import com.bloatit.framework.exceptions.highlevel.ShallNotPassException; import com.bloatit.framework.utils.PageIterable; import com.bloatit.framework.utils.Sorter; import com.bloatit.framework.utils.Sorter.Order; import com.bloatit.framework.utils.datetime.DateUtils; import com.bloatit.framework.utils.i18n.DateLocale.FormatStyle; import com.bloatit.framework.utils.i18n.Language; import com.bloatit.framework.webprocessor.components.HtmlDiv; import com.bloatit.framework.webprocessor.components.HtmlImage; import com.bloatit.framework.webprocessor.components.HtmlLink; import com.bloatit.framework.webprocessor.components.HtmlParagraph; import com.bloatit.framework.webprocessor.components.HtmlSpan; import com.bloatit.framework.webprocessor.components.HtmlTitle; import com.bloatit.framework.webprocessor.components.PlaceHolderElement; import com.bloatit.framework.webprocessor.components.advanced.HtmlTable; import com.bloatit.framework.webprocessor.components.advanced.HtmlTable.HtmlLineTableModel; import com.bloatit.framework.webprocessor.components.advanced.HtmlTable.HtmlLineTableModel.EmptyCell; import com.bloatit.framework.webprocessor.components.advanced.HtmlTable.HtmlLineTableModel.HtmlTableCell; import com.bloatit.framework.webprocessor.components.advanced.HtmlTable.HtmlLineTableModel.HtmlTableLine; import com.bloatit.framework.webprocessor.components.meta.HtmlElement; import com.bloatit.framework.webprocessor.components.meta.HtmlMixedText; import com.bloatit.framework.webprocessor.components.meta.HtmlNode; import com.bloatit.framework.webprocessor.context.Context; import com.bloatit.model.Actor; import com.bloatit.model.BankTransaction; import com.bloatit.model.Contribution; import com.bloatit.model.ContributionInvoice; import com.bloatit.model.FeatureImplementation; import com.bloatit.model.Image; import com.bloatit.model.Invoice; import com.bloatit.model.Member; import com.bloatit.model.Milestone; import com.bloatit.model.MoneyWithdrawal; import com.bloatit.model.Team; import com.bloatit.model.right.UnauthorizedOperationException; import com.bloatit.model.right.UnauthorizedPrivateAccessException; import com.bloatit.model.right.UnauthorizedReadOnlyBankDataAccessException; import com.bloatit.web.WebConfiguration; import com.bloatit.web.linkable.features.FeatureTabPane; import com.bloatit.web.linkable.features.FeatureTabPane.FeatureTabKey; import com.bloatit.web.linkable.master.HtmlDefineParagraph; import com.bloatit.web.linkable.master.HtmlPageComponent; import com.bloatit.web.linkable.softwares.SoftwaresTools; import com.bloatit.web.url.CancelContributionPageUrl; import com.bloatit.web.url.CancelWithdrawMoneyActionUrl; import com.bloatit.web.url.ContributionInvoiceResourceUrl; import com.bloatit.web.url.FeaturePageUrl; import com.bloatit.web.url.InvoiceResourceUrl; public class AccountComponent extends HtmlPageComponent { public AccountComponent(final Team team) throws UnauthorizedOperationException { final HtmlDiv accountPage = new HtmlDiv("account_page"); add(accountPage); accountPage.add(generateAccountSolde(team)); accountPage.add(new HtmlTitle(tr("Account informations – {0}", team.getDisplayName()), 1)); accountPage.add(generateAccountMovementList(team.getContributions(), team.getBankTransactions(), team.getMoneyWithdrawals(), team.getMilestones())); } public AccountComponent(final Member me) throws UnauthorizedOperationException { final HtmlDiv accountPage = new HtmlDiv("account_page"); add(accountPage); accountPage.add(generateAccountSolde(me)); accountPage.add(new HtmlTitle(tr("Account informations – {0}", me.getDisplayName()), 1)); accountPage.add(generateAccountMovementList(me.getContributions(), me.getBankTransactions(), me.getMoneyWithdrawals(), me.getMilestones())); } private HtmlElement generateAccountSolde(final Actor<?> loggedUser) { final HtmlDiv floatRight = new HtmlDiv("float_right"); final HtmlDiv soldeBlock = new HtmlDiv("solde_block"); final HtmlDiv soldeText = new HtmlDiv("solde_text"); if (loggedUser instanceof Team) { soldeText.addText(tr("The team currently has ")); } else { soldeText.addText(tr("You currently have ")); } final HtmlDiv soldeAmount = new HtmlDiv("solde_amount"); try { soldeAmount.addText(Context.getLocalizator().getCurrency(loggedUser.getInternalAccount().getAmount()).getSimpleEuroString()); } catch (final UnauthorizedOperationException e) { throw new ShallNotPassException("Right error.", e); } soldeBlock.add(soldeText); soldeBlock.add(soldeAmount); floatRight.add(soldeBlock); return floatRight; } private HtmlElement generateAccountMovementList(final PageIterable<Contribution> contributions, final PageIterable<BankTransaction> bankTransactions, final PageIterable<MoneyWithdrawal> moneyWithdrawals, final PageIterable<Milestone> milestones) { final List<HtmlTableLine> lineList = new ArrayList<HtmlTableLine>(); final Sorter<HtmlTableLine, Date> sorter = new Sorter<HtmlTableLine, Date>(lineList); try { for (final MoneyWithdrawal moneyWithdrawal : moneyWithdrawals) { sorter.add(new MoneyWithdrawalLine(moneyWithdrawal), moneyWithdrawal.getCreationDate()); } for (final Contribution contribution : contributions) { if (contribution.getState() == com.bloatit.data.DaoContribution.ContributionState.CANCELED) { sorter.add(new ContributionCanceledLine(contribution), contribution.getCreationDate()); } else { if (contribution.getFeature().getFeatureState() != FeatureState.DISCARDED) { sorter.add(new ContributionLine(contribution), contribution.getCreationDate()); } else { sorter.add(new ContributionFailedLine(contribution), contribution.getCreationDate()); } } } for (final BankTransaction bankTransaction : bankTransactions) { if (bankTransaction.getValue().compareTo(BigDecimal.ZERO) >= 0) { if (bankTransaction.getState() == State.VALIDATED) { sorter.add(new ChargeAccountLine(bankTransaction), bankTransaction.getModificationDate()); } else if (bankTransaction.getState() == State.REFUSED) { sorter.add(new ChargeAccountFailedLine(bankTransaction), bankTransaction.getModificationDate()); } else { if (DateUtils.elapsed(bankTransaction.getModificationDate(), DateUtils.now()) > DateUtils.SECOND_PER_DAY * 1000) { // Aborted sorter.add(new ChargeAccountAbordedLine(bankTransaction), bankTransaction.getModificationDate()); } } } } for (final Milestone milestone : milestones) { if (milestone.getAmountPaid().compareTo(BigDecimal.ZERO) > 0) { sorter.add(new MilestoneLine(milestone), milestone.getLastPaymentDate()); } } } catch (final UnauthorizedOperationException e) { throw new ShallNotPassException("Right fail on account page", e); } sorter.performSort(Order.DESC); if (sorter.size() == 0) { return new HtmlParagraph(Context.tr("No operations occured on your account yet.")); } final HtmlLineTableModel model = new HtmlLineTableModel(); for (final HtmlTableLine line : lineList) { model.addLine(line); } final HtmlTable table = new HtmlTable(model); return table; } private static class ContributionLine extends HtmlTableLine { private final Contribution contribution; public ContributionLine(final Contribution contribution) throws UnauthorizedOperationException { this.contribution = contribution; addCell(new MoneyVariationCell(false)); addCell(new TitleCell(contribution.getCreationDate(), generateContributionTitle())); addCell(new DescriptionCell(tr("Feature summary"), generateContributionDescription())); addCell(new MoneyCell(contribution.getAmount().negate())); } private HtmlDiv generateContributionDescription() throws UnauthorizedPrivateAccessException { final HtmlDiv description = new HtmlDiv("description"); final HtmlSpan softwareLink = new SoftwaresTools.Link(contribution.getFeature().getSoftware()); final HtmlMixedText descriptionString = new HtmlMixedText(Context.tr("{0} (<0::>)", contribution.getFeature() .getDescription() .getTranslationOrDefault(Language.fromLocale(Context.getLocalizator() .getLocale())) .getTitle()), softwareLink); final HtmlSpan status = new HtmlSpan(); switch (contribution.getFeature().getFeatureState()) { case DEVELOPPING: status.addText(tr("In development")); break; case FINISHED: status.addText(tr("Success")); break; case DISCARDED: status.addText(tr("Failed")); break; case PENDING: case PREPARING: final HtmlLink cancelLink = new CancelContributionPageUrl(contribution).getHtmlLink(Context.tr("(Cancel contribution)")); status.addText(tr("Funding ")); status.add(cancelLink); break; } description.add(new HtmlDefineParagraph(tr("Description: "), descriptionString)); description.add(new HtmlDefineParagraph(tr("Status: "), status)); final PageIterable<ContributionInvoice> invoices = contribution.getInvoices(); if (invoices.size() > 1) { final HtmlSpan invoiceList = new HtmlSpan(); for (final ContributionInvoice invoice : invoices) { invoiceList.addText(" "); invoiceList.add(new ContributionInvoiceResourceUrl(invoice).getHtmlLink(Context.tr("milestone {0}", invoice.getMilestone() .getPosition()))); } description.add(new HtmlDefineParagraph(tr("Invoices: "), invoiceList)); } else if (invoices.size() == 1) { final HtmlSpan invoiceList = new HtmlSpan(); for (final ContributionInvoice invoice : invoices) { invoiceList.addText(" "); invoiceList.add(new ContributionInvoiceResourceUrl(invoice).getHtmlLink(invoice.getInvoiceNumber())); } description.add(new HtmlDefineParagraph(tr("Invoice: "), invoiceList)); } return description; } private HtmlDiv generateContributionTitle() { final HtmlDiv title = new HtmlDiv("title"); final FeaturePageUrl featurePageUrl = new FeaturePageUrl(contribution.getFeature(), FeatureTabKey.contributions); featurePageUrl.setAnchor(FeatureTabPane.FEATURE_TAB_PANE); title.add(new HtmlMixedText(tr("Contributed to a <0::feature>"), featurePageUrl.getHtmlLink())); return title; } } private static class ContributionFailedLine extends HtmlTableLine { private final Contribution contribution; public ContributionFailedLine(final Contribution contribution) throws UnauthorizedOperationException { setCssClass("failed_line"); this.contribution = contribution; addCell(new EmptyCell()); addCell(new TitleCell(contribution.getCreationDate(), generateContributionTitle())); addCell(new EmptyCell()); addCell(new MoneyCell(contribution.getAmount().negate())); } private HtmlDiv generateContributionTitle() { final HtmlDiv title = new HtmlDiv("title"); final FeaturePageUrl featurePageUrl = new FeaturePageUrl(contribution.getFeature(), FeatureTabKey.contributions); featurePageUrl.setAnchor(FeatureTabPane.FEATURE_TAB_PANE); title.add(new HtmlMixedText(tr("Contributed to a failed <0::feature>"), featurePageUrl.getHtmlLink())); return title; } } /** * */ private static class ContributionCanceledLine extends HtmlTableLine { private final Contribution contribution; public ContributionCanceledLine(final Contribution contribution) throws UnauthorizedOperationException { setCssClass("failed_line"); this.contribution = contribution; addCell(new EmptyCell()); addCell(new TitleCell(contribution.getCreationDate(), generateContributionTitle())); addCell(new EmptyCell()); addCell(new MoneyCell(contribution.getAmount().negate())); } private HtmlDiv generateContributionTitle() { final HtmlDiv title = new HtmlDiv("title"); final FeaturePageUrl featurePageUrl = new FeaturePageUrl(contribution.getFeature(), FeatureTabKey.contributions); title.add(new HtmlMixedText(tr("Contribution canceled (<0::feature>)"), featurePageUrl.getHtmlLink())); return title; } } private static class MilestoneLine extends HtmlTableLine { private final Milestone milestone; public MilestoneLine(final Milestone milestone) throws UnauthorizedOperationException { this.milestone = milestone; addCell(new MoneyVariationCell(true)); addCell(new TitleCell(milestone.getLastPaymentDate(), generateMilestoneTitle())); addCell(new DescriptionCell(tr("Feature summary"), generateMilestoneDescription())); addCell(new MoneyCell(milestone.getAmountPaid())); } private HtmlDiv generateMilestoneDescription() { final HtmlDiv description = new HtmlDiv("description"); final FeatureImplementation feature = milestone.getOffer().getFeature(); final HtmlSpan softwareLink = new SoftwaresTools.Link(feature.getSoftware()); final HtmlMixedText descriptionString = new HtmlMixedText(Context.tr("{0} (<0::>)", feature.getDescription() .getTranslationOrDefault(Language.fromLocale(Context.getLocalizator() .getLocale())) .getTitle()), softwareLink); String statusString = ""; switch (feature.getFeatureState()) { case DEVELOPPING: statusString = tr("In development"); break; case FINISHED: statusString = tr("Success"); break; case DISCARDED: statusString = tr("Failed"); break; case PENDING: case PREPARING: statusString = tr("Funding"); break; } description.add(new HtmlDefineParagraph(tr("Description: "), descriptionString)); description.add(new HtmlDefineParagraph(tr("Status: "), statusString)); return description; } private HtmlDiv generateMilestoneTitle() { final HtmlDiv title = new HtmlDiv("title"); final FeaturePageUrl featurePageUrl = new FeaturePageUrl(milestone.getOffer().getFeature(), FeatureTabKey.offers); title.add(new HtmlMixedText(tr("Payed for <0::milestone> development"), featurePageUrl.getHtmlLink())); return title; } } private static class MoneyWithdrawalLine extends HtmlTableLine { private final MoneyWithdrawal moneyWithdrawal; private final boolean failed; public MoneyWithdrawalLine(final MoneyWithdrawal moneyWithdrawal) throws UnauthorizedOperationException { this.moneyWithdrawal = moneyWithdrawal; failed = (moneyWithdrawal.getState() == DaoMoneyWithdrawal.State.CANCELED || moneyWithdrawal.getState() == DaoMoneyWithdrawal.State.REFUSED); if (failed) { setCssClass("failed_line"); addCell(new EmptyCell()); } else { addCell(new MoneyVariationCell(false)); } addCell(new TitleCell(moneyWithdrawal.getCreationDate(), generateTitle())); if (!failed) { addCell(new DescriptionCell(tr("Withdrawal summary"), generateContributionDescription())); } else { addCell(new DescriptionCell("", generateContributionDescription())); } addCell(new MoneyCell(moneyWithdrawal.getAmountWithdrawn().negate())); } private HtmlDiv generateContributionDescription() throws UnauthorizedOperationException { final HtmlDiv description = new HtmlDiv("description"); String statusString = ""; switch (moneyWithdrawal.getState()) { case CANCELED: statusString = tr("Canceled"); break; case REFUSED: statusString = tr("Rejected"); break; case COMPLETE: statusString = tr("Complete"); break; case REQUESTED: statusString = tr("Requested"); break; case TREATED: statusString = tr("In progress"); break; } description.add(new HtmlDefineParagraph(tr("IBAN: "), moneyWithdrawal.getIBAN())); description.add(new HtmlDefineParagraph(tr("Reference: "), moneyWithdrawal.getReference())); if (moneyWithdrawal.getState() == DaoMoneyWithdrawal.State.REQUESTED) { final CancelWithdrawMoneyActionUrl cancelUrl = new CancelWithdrawMoneyActionUrl(Context.getSession().getShortKey(), moneyWithdrawal); final HtmlMixedText statusWithCancel = new HtmlMixedText(tr("{0} (<0::cancel withdrawal>)", statusString), cancelUrl.getHtmlLink()); description.add(new HtmlDefineParagraph(tr("Status: "), statusWithCancel)); } else { description.add(new HtmlDefineParagraph(tr("Status: "), statusString)); } return description; } private HtmlDiv generateTitle() throws UnauthorizedReadOnlyBankDataAccessException { final HtmlDiv title = new HtmlDiv("title"); if (failed) { if (moneyWithdrawal.getState() == DaoMoneyWithdrawal.State.CANCELED) { title.addText(tr("Withdrew money canceled")); } else { title.addText(tr("Withdrew money failure")); } } else { title.addText(tr("Withdrew money")); } return title; } } private static class ChargeAccountLine extends HtmlTableLine { private final BankTransaction bankTransaction; public ChargeAccountLine(final BankTransaction bankTransaction) { this.bankTransaction = bankTransaction; try { addCell(new MoneyVariationCell(true)); addCell(new TitleCell(bankTransaction.getCreationDate(), generateChargeAccountTitle())); addCell(new DescriptionCell(tr("Account loading summary"), generateChargeAccountDescription())); addCell(new MoneyCell(bankTransaction.getValue())); } catch (final UnauthorizedOperationException e) { addCell(new EmptyCell()); addCell(new EmptyCell()); addCell(new EmptyCell()); addCell(new EmptyCell()); Context.getSession().notifyWarning(Context.tr("You are not allowed to see this account informations.")); } } private HtmlDiv generateChargeAccountDescription() throws UnauthorizedOperationException { final HtmlDiv description = new HtmlDiv("description"); description.add(new HtmlDefineParagraph(tr("Total cost: "), Context.getLocalizator() .getCurrency(bankTransaction.getValuePaid()) .getTwoDecimalEuroString())); final Invoice invoice = bankTransaction.getInvoice(); if (invoice != null) { description.add(new HtmlDefineParagraph(tr("Invoice: "), new InvoiceResourceUrl(invoice).getHtmlLink("invoice-" + invoice.getInvoiceNumber() + ".pdf"))); } return description; } private HtmlDiv generateChargeAccountTitle() { final HtmlDiv title = new HtmlDiv("title"); title.addText(tr("Charged account")); return title; } } private static class ChargeAccountFailedLine extends HtmlTableLine { public ChargeAccountFailedLine(final BankTransaction bankTransaction) { setCssClass("failed_line"); try { addCell(new EmptyCell()); addCell(new TitleCell(bankTransaction.getCreationDate(), generateChargeAccountFailedTitle())); addCell(new EmptyCell()); addCell(new MoneyCell(bankTransaction.getValue())); } catch (final UnauthorizedOperationException e) { addCell(new EmptyCell()); addCell(new EmptyCell()); addCell(new EmptyCell()); addCell(new EmptyCell()); Context.getSession().notifyWarning(Context.tr("You are not allowed to see this account informations.")); } } private HtmlDiv generateChargeAccountFailedTitle() { final HtmlDiv title = new HtmlDiv("title"); title.addText(tr("Charging account failure")); return title; } } private static class ChargeAccountAbordedLine extends HtmlTableLine { public ChargeAccountAbordedLine(final BankTransaction bankTransaction) { setCssClass("failed_line"); try { addCell(new EmptyCell()); addCell(new TitleCell(bankTransaction.getCreationDate(), generateChargeAccountFailedTitle())); addCell(new EmptyCell()); addCell(new MoneyCell(bankTransaction.getValue())); } catch (final UnauthorizedOperationException e) { addCell(new EmptyCell()); addCell(new EmptyCell()); addCell(new EmptyCell()); addCell(new EmptyCell()); Context.getSession().notifyWarning(Context.tr("You are not allowed to see this account informations.")); } } private HtmlDiv generateChargeAccountFailedTitle() { final HtmlDiv title = new HtmlDiv("title"); title.addText(tr("Charging account aborted")); return title; } } private static class MoneyVariationCell extends HtmlTableCell { private final boolean up; public MoneyVariationCell(final boolean up) { super("money_variation_cell"); this.up = up; } @Override public HtmlNode getBody() { if (up) { return new HtmlImage(new Image(WebConfiguration.getImgMoneyUpSmall()), "money up"); } return new HtmlImage(new Image(WebConfiguration.getImgMoneyDownSmall()), "money down"); } } private static class TitleCell extends HtmlTableCell { private final Date date; private final HtmlDiv title; public TitleCell(final Date date, final HtmlDiv title) { super("title_cell"); this.date = date; this.title = title; } @Override public HtmlNode getBody() { final PlaceHolderElement titleCell = new PlaceHolderElement(); final HtmlDiv dateDiv = new HtmlDiv("date"); dateDiv.addText(Context.getLocalizator().getDate(date).toString(FormatStyle.LONG)); titleCell.add(dateDiv); titleCell.add(title); return titleCell; } } private static class DescriptionCell extends HtmlTableCell { private final String title; private final HtmlDiv description; public DescriptionCell(final String title, final HtmlDiv description) { super("description_cell"); this.title = title; this.description = description; } @Override public HtmlNode getBody() { final PlaceHolderElement descriptionCell = new PlaceHolderElement(); descriptionCell.addText(title); descriptionCell.add(description); return descriptionCell; } } private static class MoneyCell extends HtmlTableCell { private final BigDecimal amount; public MoneyCell(final BigDecimal amount) { super("money"); this.amount = amount; } @Override public HtmlNode getBody() { final HtmlDiv moneyCell = new HtmlDiv(); String amountString = Context.getLocalizator().getCurrency(amount).getSimpleEuroString(); if (amount.compareTo(BigDecimal.ZERO) > 0) { amountString = "+" + amountString; moneyCell.setCssClass("money_up"); } else { moneyCell.setCssClass("money_down"); } moneyCell.addText(amountString); return moneyCell; } } }