Java tutorial
/** * @author bookingnet * @see License at abookingnet.com/license * @version 2.00 */ package net.cbtltd.client.panel; import java.util.ArrayList; import java.util.Date; import net.cbtltd.client.AbstractRoot; import net.cbtltd.client.Component; import net.cbtltd.client.GuardedRequest; import net.cbtltd.client.LocalRequest; import net.cbtltd.client.field.AbstractField; import net.cbtltd.client.field.AbstractField.Level; import net.cbtltd.client.field.CommandButton; import net.cbtltd.client.field.DateField; import net.cbtltd.client.field.DoubleField; import net.cbtltd.client.field.DoubleunitField; import net.cbtltd.client.field.HelpLabel; import net.cbtltd.client.field.ListField; import net.cbtltd.client.field.MessagePanel; import net.cbtltd.client.field.SuggestField; import net.cbtltd.client.field.TableField; import net.cbtltd.client.field.TextAreaField; import net.cbtltd.client.field.TextField; import net.cbtltd.client.form.Transition; import net.cbtltd.client.resource.Hosts; import net.cbtltd.client.resource.journal.JournalBundle; import net.cbtltd.client.resource.journal.JournalConstants; import net.cbtltd.client.resource.journal.JournalCssResource; import net.cbtltd.client.widget.RazorWidget; import net.cbtltd.client.widget.book.PayWidgetItem; import net.cbtltd.shared.Account; import net.cbtltd.shared.Currency; import net.cbtltd.shared.Event; import net.cbtltd.shared.Finance; import net.cbtltd.shared.JSONRequest; import net.cbtltd.shared.Journal; import net.cbtltd.shared.License; import net.cbtltd.shared.Model; import net.cbtltd.shared.NameId; import net.cbtltd.shared.NameIdAction; import net.cbtltd.shared.Party; import net.cbtltd.shared.Price; import net.cbtltd.shared.Product; import net.cbtltd.shared.Report; import net.cbtltd.shared.Reservation; import net.cbtltd.shared.Service; import net.cbtltd.shared.Table; import net.cbtltd.shared.Tax; import net.cbtltd.shared.Time; import net.cbtltd.shared.Unit; import net.cbtltd.shared.finance.CurrencyNameId; import net.cbtltd.shared.finance.FinanceRead; import net.cbtltd.shared.journal.EventJournal; import net.cbtltd.shared.journal.JournalCreate; import net.cbtltd.shared.journal.JournalDelete; import net.cbtltd.shared.journal.JournalItemTable; import net.cbtltd.shared.journal.JournalRead; import net.cbtltd.shared.journal.JournalUpdate; import net.cbtltd.shared.party.PartyLicense; import net.cbtltd.shared.party.PartyRead; import net.cbtltd.shared.reservation.ReservationEntities; import net.cbtltd.shared.tax.TaxTable; import com.allen_sauer.gwt.log.client.Log; import com.bookingnet.config.RazorConfig; import com.google.gwt.cell.client.NumberCell; import com.google.gwt.cell.client.TextCell; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.jsonp.client.JsonpRequestBuilder; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.view.client.NoSelectionModel; import com.google.gwt.view.client.SelectionChangeEvent; /** * The Class JournalPopup is the primary accounting panel for several different types of financial transaction. * The financial ledger is a store of transactions which have an attribute for each aspect including: * the user which entered the transaction * the physical location at which the transaction was entered * the type of transaction or process (Journal, Payment, Purchase, PurchaseSale, Receipt, Reservation Sale, Sale) * the effective date of the transaction * the due date for any follow up action * the date on which follow up action was done * an optional activity to which the transaction is allocated (reservation, Task) * the organization to which the transaction belongs * the ledger account to which the transaction is posted * the sub-ledger (entity type) to which the transaction is posted * the sub-account (entity ID) to which the transaction is posted * the debit amount (financial value) of the transaction * the credit amount (financial value) of the transaction * the currency code of the transaction * an optional description of the transaction * an optional location at which the transaction took place * an optional physical quantity of the transaction * an optional unit of measure of this physical quantity * * Transactions are grouped by event so that their total amount is zero (debit amount _ credit amount = 0) * This grouping is determined by the posting rules which depend on the type of process, the tax regime, * the organizations, locations, currencies and entities involved, and so on. * * For example, all financial processes have balanced debit and credit entries. * Taxable transactions result in entries to debit or credit the relevant tax jurisdiction(s) in addition the principal transactions. * A payment made by one organization by another results in matching loan account entries in the ledger of each organization. * A receipt in one currency to settle a debt in another results in postings to currency control accounts. * * Accountants are familiar with these concepts which are often represented by "T" diagrams * This class implements these posting rules for a number of process types including: * Journal, Payment, Purchase, PurchaseSale, Receipt, Reservation Sale and Sale. * * The class controls visibility of fields to those relevant to each type of process, * and it validates data and creates transactions based on the posting rules implemented for each process type. * A process can be reversed (a Credit Note is the reverse of a Sale, for example) by setting the reversed field to true. */ public class JournalPopup extends AbstractPopup<Event<Journal>> { private static final JournalConstants CONSTANTS = GWT.create(JournalConstants.class); private static final Hosts HOSTS = GWT.create(Hosts.class); private static final JournalBundle BUNDLE = JournalBundle.INSTANCE; private static final JournalCssResource CSS = BUNDLE.css(); private static final int JOURNAL_ROWS = 140; //Events private static GuardedRequest<Event<Journal>> journalDelete; private static GuardedRequest<Event<Journal>> journalSave; private static GuardedRequest<Event<Journal>> journalUpdate; private static GuardedRequest<Event<Journal>> journalCreate; private static GuardedRequest<Event<Journal>> journalRead; private static GuardedRequest<Finance> financeRead; private static GuardedRequest<Party> organizationRead; private static GuardedRequest<Party> organizationLicense; private static GuardedRequest<Report> reportView; private static GuardedRequest<Table<Tax>> taxTable; private static Label reversedLabel; private static Label titleField; private static Image reportButton; private static Image reportLoader; private static SuggestField eventnameField; private static SuggestField entityField; private static Image entityButton; private static SuggestField supplierField; private static ListField processField; private static SuggestField accountField; private static ListField financeField; private static DateField eventdateField; private static DoubleField exchangerateField; private static DoubleField debitamountField; private static DoubleField creditamountField; private static DoubleunitField amountField; private static ListField taxField; private static TextAreaField descriptionField; private static HorizontalPanel logoImages; private static TextField cardholderField; private static TextField cardnumberField; private static HelpLabel carddetailLabel; private static ListField cardmonthField; private static ListField cardyearField; private static TextField cardcodeField; private static boolean isCardPayment = false; private static boolean isCardReceipt = false; private static CommandButton itemButton; private static CommandButton saveButton; private static CommandButton cancelButton; private static Button submitButton; private static Image loader; private static TableField<Journal> journalTable; private static TableField<EventJournal> parentField; private static Journal selectedjournal; private static Finance finance; private static Party organization; private static boolean hasTaxnumber() { return organization == null ? false : organization.hasTaxnumber(); } private static ReservationEntities reservationentities; private static Event.Type type = Event.Type.Journal; private static ArrayList<Price> prices; private static ArrayList<Tax> taxes; private static Price price = null; private static int priceIndex = 0; private static Party.Type[] partytypes = { null, Party.Type.Supplier, Party.Type.Supplier, Party.Type.Supplier, Party.Type.Customer, Party.Type.Customer, Party.Type.Customer }; private static boolean reversed = false; private static String message; /** * Instantiates a new journal pop up panel. */ public JournalPopup() { super(false); AbstractField.CSS.ensureInjected(); CSS.ensureInjected(); createActions(); setWidget(createContent()); setModal(true); setStylePrimaryName(AbstractField.CSS.cbtAbstractPopup()); } private static JournalPopup instance; /** * Gets the single instance of JournalPopup and resets its field values. * * @return single instance of JournalPopup */ public static synchronized JournalPopup getInstance() { if (instance == null) { instance = new JournalPopup(); organizationRead.execute(); } prices = null; price = null; financeField.onRefresh(); eventdateField.setValue(new Date()); accountField.setValue(null); entityField.setIds(null); entityField.setType(null); selectedjournal = null; parentField = null; reversed = false; finance = null; cardholderField.setValue(""); cardnumberField.setValue(""); cardmonthField.setValue(""); cardyearField.setValue(""); cardcodeField.setValue(""); message = null; return instance; } /** * Prepare the journal pop up panel for display and send a request to get the data from the JournalService. * On receipt of the response the pop up panel is displayed in the center of the screen. * * @param eventname the process reference code (event name) */ public void show(String eventname) { parentField = null; eventnameField.setValue(eventname); journalRead.execute(); } /** * Prepare the journal pop up panel for display and send a request to get the data from the JournalService. * On receipt of the response the pop up panel is displayed in the center of the screen. * * @param eventaction the ID of the reservation or task to which the process belongs * @param reservationentities the information about the reservation to which the process belongs. * @param parentField the field from which the process is called, typically a list of financial transactions. */ public void show(EventJournal eventaction, ReservationEntities reservationentities, TableField<EventJournal> parentField) { JournalPopup.parentField = parentField; JournalPopup.reservationentities = reservationentities; eventnameField.setValue(eventaction.getId()); journalRead.execute(); } /** * Prepare the journal pop up panel and send a request to create a new instance to the JournalService. * On receipt of the response the pop up panel is displayed in the center of the screen. * * @param type the type of process to be created * @param reservationentities the information about the reservation to which the process belongs. * @param parentField the field from which the process is called, typically a list of financial transactions. */ public void show(Event.Type type, ReservationEntities reservationentities, TableField<EventJournal> parentField) { JournalPopup.type = type; JournalPopup.parentField = parentField; JournalPopup.reservationentities = reservationentities; onReset(Event.INITIAL); processField.setValue(type.name()); journalCreate.execute(true); } /** * Prepare the journal pop up panel and send a request to create a new instance to the JournalService. * On receipt of the response the pop up panel is displayed in the center of the screen. * * @param type the type of process to be created * @param reservation_form the reservation to which the process is to be allocated. * @param reservationentities the information about the reservation to which the process belongs. * @param parentField the field from which the process is called, typically a list of financial transactions. */ public void show(Event.Type type, TableField<EventJournal> parentField) { show(type, null, null, null, parentField); } /** * Prepare the journal pop up panel and send a request to create a new instance to the JournalService. * On receipt of the response the pop up panel is displayed in the center of the screen. * * @param type the type of process to be created * @param reservation the reservation to which the process is to be allocated. * @param reservationentities the information about the reservation to which the process belongs. * @param parentField the field from which the process is called, typically a list of financial transactions. */ public void show(Event.Type type, Reservation reservation, ReservationEntities reservationentities, TableField<EventJournal> parentField) { show(type, reservation, null, reservationentities, parentField); } /** * Prepare the journal pop up panel and send a request to create a new instance. * On receipt of the response the pop up panel is displayed in the center of the screen. * * @param type the type of process to be created * @param reservation the reservation to which the process is to be allocated. * @param price the priced feature to be invoiced * @param reservationentities the information about the reservation to which the process belongs. * @param parentField the field from which the process is called, typically a list of financial transactions. */ public void show(Event.Type type, Reservation reservation, ArrayList<Price> prices, ReservationEntities reservationentities, TableField<EventJournal> parentField) { if (GuardedRequest.isSending()) { new MessagePanel(Level.VERBOSE, AbstractField.CONSTANTS.allLoading()).center(); } else { JournalPopup.type = type; JournalPopup.prices = prices; JournalPopup.priceIndex = 0; JournalPopup.parentField = parentField; JournalPopup.reservationentities = reservationentities; onReset(Event.INITIAL); processField.setValue(type.name()); amountField.setValue(0.0); amountField.setUnitvalue(AbstractRoot.getCurrency()); if (reservationentities == null) { descriptionField.setValue(Model.BLANK); } else if (type == Event.Type.Journal) { descriptionField.setValue(Model.BLANK); } else if (type == Event.Type.ReservationSale) { nextPrice(); return; } else { descriptionField.setValue(reservationentities.getReservation().getName()); } journalCreate.execute(true); } } /* * Gets the default reservation sale description. * * @return the default reservation sale description. */ private String getDescriptionReservationSale() { StringBuilder sb = new StringBuilder(); sb.append(CONSTANTS.descriptionReservationSale()).append(reservationentities.getReservation().getName()); if (reservationentities.hasCustomer()) { sb.append(" for ").append(reservationentities.getCustomer().getName()); } else if (reservationentities.hasAgent()) { sb.append(" for ").append(reservationentities.getAgent().getName()); } sb.append(" from ").append(AbstractRoot.getDF().format(reservationentities.getReservation().getFromdate())); sb.append(" to ").append(AbstractRoot.getDF().format(reservationentities.getReservation().getTodate())); return sb.toString(); } /* * Gets the next available price, or hides the panel if there are none more. * Creates a PurchaseSale transaction if the price has a supplier, else creates a Sale transaction. */ private void nextPrice() { while (prices != null && !prices.isEmpty() && prices.size() > priceIndex) { price = prices.get(priceIndex++); if (price.hasType(Price.TAX_INCLUDED)) { continue; } accountField.setValue(Account.SALES_REVENUE); amountField.setValue(price.getTotalvalue()); processField.setValue(type.name()); amountField.setUnitvalue(price.getCurrency()); descriptionField.setValue(price.getName()); if (price.hasType(Price.RATE)) { descriptionField.setValue(getDescriptionReservationSale()); } else if (price.noSupplierid()) { type = Event.Type.Sale; } else { type = Event.Type.PurchaseSale; supplierField.setValue(price.getSupplierid()); } if ((price.hasType(Price.RATE) || price.hasType(Price.YIELD)) && reservationentities != null) { type = Event.Type.ReservationSale; } if ((price.hasType(Price.RATE) || price.hasType(Price.YIELD)) && reservationentities != null && reservationentities.hasAgent(entityField.getValue())) { amountField.setValue(price.getTotalvalue() * reservationentities.getDiscountfactor()); } processField.setValue(type.name()); journalCreate.execute(true); return; } if (parentField != null) { parentField.execute(true); } hide(); } /** * Handles change events. * * @param change the event when changed. */ @Override public void onChange(ChangeEvent change) { if (eventnameField.sent(change)) { journalRead.execute(); } else if (financeField.sent(change)) { financeRead.execute(); } else if (accountField.sent(change)) { setEntityAction(); } else if (entityField.sent(change) && reservationentities != null && reservationentities.hasAgent(entityField.getValue()) && price != null && (price.hasType(Price.RATE) || price.hasType(Price.YIELD))) { amountField.setValue(price.getTotalvalue() * reservationentities.getDiscountfactor()); } if (selectedjournal != null) { getValue(selectedjournal); journalTable.redraw(); } setView(); } /* Sets which fields are visible depending on the process type and security of the service, and displays the journal pop up panel. */ private void setView() { type = processField.noValue() ? Event.Type.Journal : Event.Type.valueOf(processField.getValue()); reversedLabel.setVisible(journalTable.noValue()); titleField.setText( reversed ? CONSTANTS.reversedNames()[type.ordinal()] : CONSTANTS.processNames()[type.ordinal()]); boolean isJournal = processField.hasValue(Event.Type.Journal.name()); boolean isPayment = processField.hasValue(Event.Type.Payment.name()); boolean isPurchase = processField.hasValue(Event.Type.Purchase.name()); boolean isReceipt = processField.hasValue(Event.Type.Receipt.name()); boolean isSale = processField.hasValue(Event.Type.Sale.name()); boolean isPurchaseSale = processField.hasValue(Event.Type.PurchaseSale.name()); boolean isReservationSale = processField.hasValue(Event.Type.ReservationSale.name()); boolean isSecure = Window.Location.getHref().startsWith(HOSTS.jsonUrl().substring(0, 5)); isCardPayment = isSecure && isPayment && entityField.hasValue(Party.CBT_LTD_PARTY); isCardReceipt = isSecure && isReceipt && financeField.hasValue(Finance.CBT_ZAR_FINANCE); boolean isCardVisible = isCardPayment || isCardReceipt; boolean isCardSelected = (isCardPayment && cardnumberField.hasValue()) || isCardReceipt; if (isPayment || isReceipt) { accountField.setValue(Account.FINANCE); } else if (isPurchase) { accountField.setType(Account.Type.Expense.name()); } else if (isSale) { accountField.setType(Account.Type.Income.name()); } else if (isJournal) { accountField.setType(null); } // else if (isReservationSale) {center(); return;} entityField.setLabel(CONSTANTS.subaccountLabels()[type.ordinal()]); entityButton.setVisible(type != Event.Type.ReservationSale && type != Event.Type.Journal); if (reservationentities != null && reservationentities.getIds() != null) { entityField.setIds(reservationentities.getIds()); } processField.setEnabled(journalTable.noValue()); eventnameField.setEnabled(journalTable.noValue()); eventdateField.setEnabled(journalTable.noValue()); journalTable.setVisible(journalTable.hasValue()); financeField.setVisible(isPayment || isReceipt || isPurchase || isPurchaseSale); supplierField.setVisible(isPurchaseSale); accountField.setVisible(isJournal || isPurchase || isSale); amountField.setVisible(!isJournal); // amountField.setUnitenabled(!isReservationSale); debitamountField.setVisible(isJournal); creditamountField.setVisible(isJournal); taxField.setVisible((isPurchase || isSale) && hasTaxnumber()); exchangerateField.setVisible(finance != null && !finance.hasCurrency(amountField.getUnitvalue())); exchangerateField.setLabel(getExchangeLabel()); logoImages.setVisible(isCardVisible); cardholderField.setVisible(isCardVisible); cardnumberField.setVisible(isCardVisible); carddetailLabel.setVisible(isCardVisible); cardmonthField.setVisible(isCardVisible); cardyearField.setVisible(isCardVisible); cardcodeField.setVisible(isCardVisible); itemButton.setVisible(!isCardSelected); saveButton.setVisible(!isCardSelected && journalTable.hasValue()); submitButton.setVisible(isCardSelected); center(); } /** * Gets the current journal instance. * * @return the current journal instance. */ @Override public Event<Journal> getValue() { return getValue(new Event<Journal>()); } /** * Updates the event parameter with the current journal field values. * * @param event the event action to be updated with current journal field values. * @return the action with the updates. */ public Event<Journal> getValue(Event<Journal> event) { event.setState(state); event.setOrganizationid(AbstractRoot.getOrganizationid()); event.setActorid(AbstractRoot.getActorid()); event.setProcess(processField.getValue()); event.setId(eventnameField.getValue()); event.setName(eventnameField.getName()); event.setActivity(NameId.Type.Reservation.name()); event.setParentid(reservationentities == null ? null : reservationentities.getId()); event.setDate(Time.getDateServer(eventdateField.getValue())); event.setNotes(message); event.setProcess(processField.getValue()); event.setType(Event.ACCOUNTING); //TODO: event.setItems(journalTable.getValue()); Log.debug("getValue " + event); return event; } /** * Sets the journal field values with the event parameter. * * @param event the event action to update the current journal field values. */ public void setValue(Event<Journal> event) { Log.debug("setValue " + event); if (event == null) { onReset(Event.CREATED); } else { setResetting(true); onStateChange(event.getState()); processField.setValue(event.getProcess()); eventnameField.setValue(event.getId()); eventdateField.setValue(Time.getDateClient(event.getDate())); journalTable.setValue(event.getItems()); setValue((Journal) journalTable.getFirstItem()); onOptionChange(event.getDonedate() == null ? Component.ENABLED : Component.DISABLED); setView(); taxTable.execute(); setResetting(false); } } /* * Updates the parameter journal line item to the current journal field values. * * @param journal line item to be updated. */ private Journal getValue(Journal journal) { journal.setAccountid(accountField.getValue()); if (financeField.isVisible()) { journal.setEntitytype(NameId.Type.Finance.name()); journal.setEntityid(financeField.getValue()); } if (entityField.isVisible()) { journal.setEntitytype(NameId.Type.Party.name()); journal.setEntityid(entityField.getValue()); } journal.setDebitamount(debitamountField.getValue()); journal.setCreditamount(creditamountField.getValue()); journal.setDescription(descriptionField.getValue()); return journal; } /* * Sets the current journal field values with the parameter journal line item. * * @param journal line item with which to update the fields. */ private void setValue(Journal journal) { if (journal == null) { return; } accountField.setValue(journal.getAccountid()); if (journal.hasEntitytype(NameId.Type.Finance)) { financeField.setValue(journal.getEntityid()); } else if (journal.hasEntitytype(NameId.Type.Party)) { entityField.setValue(journal.getEntityid()); } amountField.setValue(journal.getAmount()); amountField.setUnitvalue(journal.getCurrency()); debitamountField.setValue(journal.getDebitamount()); creditamountField.setValue(journal.getCreditamount()); descriptionField.setValue(journal.getDescription()); } private Finance getValue(Finance finance) { finance.setOrganizationid(AbstractRoot.getOrganizationid()); finance.setId(financeField.getValue()); return finance; } /** * Sets the bank or cash account to be used for payments and receipts. * * @param finance the new bank or cash account. */ public void setValue(Finance finance) { JournalPopup.finance = finance; if (finance != null) { amountField.setUnitvalue(finance.getCurrency()); } } /* * Updates the parameter organization (party) with the current session organization ID. * * @param organization the organization to be updated. */ private Party getValue(Party organization) { organization.setOrganizationid(AbstractRoot.getOrganizationid()); organization.setId(AbstractRoot.getOrganizationid()); return organization; } /* * Sets the party to be used, which may be a customer, supplier or other party to the transaction. * * @param organization the new party to be used. */ private void setValue(Party organization) { JournalPopup.organization = organization; } /* (non-Javadoc) * @see net.cbtltd.client.panel.AbstractPopup#getValue(java.lang.Object) */ private Tax getValue(TaxTable action) { if (reservationentities == null) { action.setEntitytype(NameId.Type.Party.name()); action.setEntityid(AbstractRoot.getOrganizationid()); } else { action.setEntitytype(NameId.Type.Product.name()); action.setEntityid(reservationentities.getProduct().getId()); } //action.setOrganizationid(AbstractRoot.getOrganizationid()); action.setOrderby(Tax.ID); action.setNumrows(Integer.MAX_VALUE); action.setStartrow(0); Log.debug("getValue " + action); return action; } /* Create and initialize a report instance with parameters needed to generate a printable document for this journal. */ private Report getReport() { Report report = new Report(); ; report.setOrganizationid(AbstractRoot.getOrganizationid()); report.setActorid(AbstractRoot.getActorid()); report.setFromname(eventnameField.getName()); report.setToname(eventnameField.getName()); report.setCurrency(amountField.getUnitvalue()); report.setDate(new Date()); report.setDesign(type.name()); report.setFormat(Report.PDF); report.setState(Report.CREATED); return report; } /* * Sets the field refresh actions based on the values of account and entity of the current journal. * For example, the account ACCOUNTS_PAYABLE has sub-accounts of type Supplier. * but the account ACCOUNTS_RECEIVABLE has sub-accounts of type Customer. */ private void setEntityAction() { entityField.setEnabled(true); financeField.setEnabled(true); if (accountField.hasValue(Account.ACCOUNTS_PAYABLE)) { entityField.setAction(new NameIdAction(Service.PARTY, Party.Type.Supplier.name())); } else if (accountField.hasValue(Account.ACCOUNTS_RECEIVABLE)) { entityField.setAction(new NameIdAction(Service.PARTY, Party.Type.Customer.name())); } else if (accountField.hasValue(Account.PURCHASE_SUSPENSE)) { entityField.setAction(new NameIdAction(Service.PARTY, Party.Type.Supplier.name())); } // else if(accountField.hasValue(Account.SALES_REVENUE)) {entityField.setAction(new NameIdAction(Service.PRODUCT, Product.Type.Accommodation.name()));} else if (accountField.hasValue(Account.SALES_REVENUE)) { entityField.setAction(new NameIdAction(Service.PARTY, Party.Type.Customer.name())); } else if (accountField.hasValue(Account.TRADING_LOANS)) { entityField.setAction(new NameIdAction(Service.PARTY, null)); } else if (accountField.hasValue(Account.VAT_INPUT)) { entityField.setAction(new NameIdAction(Service.PARTY, Party.Type.Jurisdiction.name())); } else if (accountField.hasValue(Account.VAT_OUTPUT)) { entityField.setAction(new NameIdAction(Service.PARTY, Party.Type.Jurisdiction.name())); } else if (accountField.hasValue(Account.FINANCE)) { entityField.setAction(new NameIdAction(Service.FINANCE, null)); } else if (accountField.hasValue(Account.COST_OF_SALES)) { entityField.setAction(new NameIdAction(Service.PRODUCT, null)); } else { entityField.setEnabled(type != Event.Type.Journal); } //needed for sales and expense accounts } /* Gets if a party (customer, supplier, jurisdiction etc) is involved in the current process. */ private boolean isParty() { return (accountField.hasValue(Account.ACCOUNTS_PAYABLE) || accountField.hasValue(Account.ACCOUNTS_RECEIVABLE) || accountField.hasValue(Account.PURCHASE_SUSPENSE) || accountField.hasValue(Account.SALES_REVENUE) || accountField.hasValue(Account.TRADING_LOANS) || accountField.hasValue(Account.VAT_INPUT) || accountField.hasValue(Account.VAT_OUTPUT)); } /* * Checks if journal exists and increment if it does. * * @param arg is the journal to be created or added */ private void getJournal(Journal arg) { if (!journalTable.noValue()) { for (Journal journal : journalTable.getValue()) { if (arg.isEqualto(journal)) { journal.addQuantity(arg.getQuantity()); journal.addDebitamount(arg.getDebitamount()); journal.addCreditamount(arg.getCreditamount()); return; } } } journalTable.addValue(arg); } /* * Post - posts a journal which has no physical attributes to the ledger. * @param organizationid is the ID of the organization of the transaction. * @param organizationname is the name of the organization of the transaction. * @param accountid is the ID of the ledger account of the transaction. * @param accountname is the name of the ledger account of the transaction. * @param entitytype is the sub-ledger (entity type) of the transaction. * @param entityid is the ID of the sub-account(entity id) of the transaction. * @param entityname is the name of the sub-account(entity name) of the transaction. * @param currency is the currency of the amount(s) in the transaction. * @param debitamount is the debit amount in the specified currency. * @param creditamount is the credit amount in the specified currency. * @param description is the description of the transaction. */ private void post(String organizationid, String organizationname, String accountid, String accountname, String entitytype, String entityid, String entityname, String currency, Double debitamount, Double creditamount, String description) { post(organizationid, organizationname, accountid, accountname, entitytype, entityid, entityname, currency, debitamount, creditamount, 1.0, Unit.EA, description); } /* * Post - posts a journal which has physical attributes to the ledger. * @param organizationid is the ID of the organization of the transaction. * @param organizationname is the name of the organization of the transaction. * @param accountid is the ID of the ledger account of the transaction. * @param accountname is the name of the ledger account of the transaction. * @param entitytype is the sub-ledger (entity type) of the transaction. * @param entityid is the ID of the sub-account(entity id) of the transaction. * @param entityname is the name of the sub-account(entity name) of the transaction. * @param currency is the currency of the amount(s) in the transaction. * @param debitamount is the debit amount in the specified currency. * @param creditamount is the credit amount in the specified currency. * @param quantity is the optional quantity of the transaction. * @param unit is the optional unit of measure of the quantity. * @param description is the description of the transaction. */ private void post(String organizationid, String organizationname, String accountid, String accountname, String entitytype, String entityid, String entityname, String currency, Double debitamount, Double creditamount, Double quantity, String unit, String description) { if (Math.abs(debitamount) < 0.01 && Math.abs(creditamount) < 0.01) { return; } getJournal(new Journal(eventnameField.getValue(), Model.ZERO, organizationid, organizationname, Model.ZERO, accountid, accountname, entitytype, entityid, entityname, reversed ? -quantity : quantity, unit, 0.0, currency, reversed ? creditamount : debitamount, reversed ? debitamount : creditamount, description)); } /* * Post Finance - posts a journal which involves bank or cash accounts (finance) to the ledger. * This automatically accounts for loan account entries if the journal organization is not the same as the finance organization. * This automatically accounts for currency conversion entries if the journal currency is not the same as the finance currency. * * @param isPayment is true if the process is a payment, false if a receipt */ private void postFinance(boolean isPayment) { if (finance == null) { Window.alert("JournalPopup postFinance " + finance); } if (finance.hasCurrency(amountField.getUnitvalue())) { post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.FINANCE, Account.FINANCE_NAME, NameId.Type.Finance.name(), financeField.getValue(), financeField.getName(), amountField.getUnitvalue(), isPayment ? 0.0 : amountField.getValue(), isPayment ? amountField.getValue() : 0.0, descriptionField.getValue()); } else { Double rate = exchangerateField.getValue(); //TODO: WebService.getRate(amountField.getUnitvalue(), finance.getCurrency(), eventdateField.getValue()); Double debitbank = isPayment ? 0.0 : Event.round(amountField.getValue() * rate, 2); Double creditbank = isPayment ? Event.round(amountField.getValue() * rate, 2) : 0.0; post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.CURRENCY_CONTROL, Account.CURRENCY_CONTROL_NAME, NameId.Type.Account.name(), Model.ZERO, Model.BLANK, amountField.getUnitvalue(), isPayment ? 0.0 : amountField.getValue(), isPayment ? amountField.getValue() : 0.0, descriptionField.getValue()); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.CURRENCY_CONTROL, Account.CURRENCY_CONTROL_NAME, NameId.Type.Account.name(), Model.ZERO, Model.BLANK, finance.getCurrency(), creditbank, debitbank, descriptionField.getValue()); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.FINANCE, Account.FINANCE_NAME, NameId.Type.Finance.name(), financeField.getValue(), financeField.getName(), finance.getCurrency(), debitbank, creditbank, descriptionField.getValue()); } if (AbstractRoot.hasOrganizationid(finance.getOwnerid())) { return; } post(finance.getOwnerid(), finance.getOwnername(), Account.TRADING_LOANS, Account.TRADING_LOANS_NAME, NameId.Type.Party.name(), AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), amountField.getUnitvalue(), isPayment ? 0.0 : amountField.getValue(), isPayment ? amountField.getValue() : 0.0, descriptionField.getValue()); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.TRADING_LOANS, Account.TRADING_LOANS_NAME, NameId.Type.Party.name(), finance.getOwnerid(), finance.getOwnername(), amountField.getUnitvalue(), isPayment ? 0.0 : amountField.getValue(), isPayment ? amountField.getValue() : 0.0, descriptionField.getValue()); } /* * Post Payment - posts a payment or receipt event to the ledger. * * @param isPayment is true if a payment, false if a receipt */ private void postPayment(boolean isPayment) { post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), isPayment ? Account.ACCOUNTS_PAYABLE : Account.ACCOUNTS_RECEIVABLE, isPayment ? Account.ACCOUNTS_PAYABLE_NAME : Account.ACCOUNTS_RECEIVABLE_NAME, NameId.Type.Party.name(), entityField.getValue(), entityField.getName(), amountField.getUnitvalue(), isPayment ? amountField.getValue() : 0.0, isPayment ? 0.0 : amountField.getValue(), descriptionField.getValue()); postFinance(isPayment); if (AbstractRoot.hasOrganizationid(Party.CBT_LTD_PARTY)) { //TODO: post reverse to manager accounts post(entityField.getValue(), entityField.getName(), isPayment ? Account.ACCOUNTS_RECEIVABLE : Account.ACCOUNTS_PAYABLE, isPayment ? Account.ACCOUNTS_RECEIVABLE_NAME : Account.ACCOUNTS_PAYABLE_NAME, NameId.Type.Party.name(), AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), amountField.getUnitvalue(), isPayment ? 0.0 : amountField.getValue(), isPayment ? amountField.getValue() : 0.0, descriptionField.getValue()); post(entityField.getValue(), entityField.getName(), Account.FINANCE, Account.FINANCE_NAME, NameId.Type.Finance.name(), Finance.CBT_USD_FINANCE, Finance.CBT_USD_FINANCE_NAME, amountField.getUnitvalue(), isPayment ? amountField.getValue() : 0.0, isPayment ? 0.0 : amountField.getValue(), descriptionField.getValue()); //Checks if license is OK organizationLicense.execute(true); } } /* * Post Payment - posts a receipt via the payment gateway. */ private void postCardReceipt() { Double amount = amountField.getValue(); Double fee = Event.round(amount * Finance.CBT_ZAR_FINANCE_FEE); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.ACCOUNTS_RECEIVABLE, Account.ACCOUNTS_RECEIVABLE_NAME, NameId.Type.Party.name(), entityField.getValue(), entityField.getName(), amountField.getUnitvalue(), 0.0, amount, descriptionField.getValue()); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.FINANCE, Account.FINANCE_NAME, NameId.Type.Finance.name(), Finance.CBT_USD_FINANCE, Finance.CBT_USD_FINANCE_NAME, amountField.getUnitvalue(), amount - fee, 0.0, descriptionField.getValue()); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.CARD_MERCHANT_FEES, Account.CARD_MERCHANT_FEES_NAME, NameId.Type.Party.name(), null, null, amountField.getUnitvalue(), fee, 0.0, descriptionField.getValue() //TODO: ); } /* * Post Purchase - posts a purchase or sale event to the ledger, including entries for taxes where appropriate. * * @param isPurchase is true if a purchase, false if a sale * @param isPurchaseSale is true if a purchase sale, false if an accommodation sale */ private void postPurchase(boolean isPurchase) { if (financeField.noValue() && entityField.noValue()) { AbstractField.addMessage(Level.ERROR, CONSTANTS.entityorfinanceError(), entityField); return; } Double taxrate = 0.0; try { taxrate = Double.valueOf(taxField.getValue()); } catch (NumberFormatException x) { AbstractField.addMessage(Level.ERROR, CONSTANTS.taxError() + taxField.getValue(), taxField); } Double totalamount = amountField.getValue(); Double taxamount = Event.round(hasTaxnumber() ? taxrate * totalamount / (100.0 + taxrate) : 0.0); Double lineamount = totalamount - taxamount; post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), accountField.getValue(), accountField.getName(), NameId.Type.Account.name(), accountField.getValue(), accountField.getName(), amountField.getUnitvalue(), isPurchase ? lineamount : 0.0, isPurchase ? 0.0 : lineamount, descriptionField.getValue()); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), isPurchase ? Account.VAT_INPUT : Account.VAT_OUTPUT, isPurchase ? Account.VAT_INPUT_NAME : Account.VAT_OUTPUT_NAME, NameId.Type.Account.name(), Model.ZERO, Model.BLANK, amountField.getUnitvalue(), isPurchase ? taxamount : 0.0, isPurchase ? 0.0 : taxamount, descriptionField.getValue()); if (financeField.hasValue() && entityField.hasValue()) { post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), isPurchase ? Account.ACCOUNTS_PAYABLE : Account.ACCOUNTS_RECEIVABLE, isPurchase ? Account.ACCOUNTS_PAYABLE_NAME : Account.ACCOUNTS_RECEIVABLE_NAME, NameId.Type.Party.name(), entityField.getValue(), entityField.getName(), amountField.getUnitvalue(), totalamount, totalamount, descriptionField.getValue()); postFinance(isPurchase); } else if (financeField.hasValue()) { postFinance(isPurchase); } else if (entityField.hasValue()) { post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), isPurchase ? Account.ACCOUNTS_PAYABLE : Account.ACCOUNTS_RECEIVABLE, isPurchase ? Account.ACCOUNTS_PAYABLE_NAME : Account.ACCOUNTS_RECEIVABLE_NAME, NameId.Type.Party.name(), entityField.getValue(), entityField.getName(), amountField.getUnitvalue(), isPurchase ? 0.0 : totalamount, isPurchase ? totalamount : 0.0, descriptionField.getValue()); } } /* * Post Purchase Sale - post a purchase made for another party. */ private void postPurchaseSale() { Double totalamount = amountField.getValue(); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.ACCOUNTS_RECEIVABLE, Account.ACCOUNTS_RECEIVABLE_NAME, NameId.Type.Party.name(), entityField.getValue(), entityField.getName(), amountField.getUnitvalue(), totalamount, 0.0, descriptionField.getValue()); post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.ACCOUNTS_PAYABLE, Account.ACCOUNTS_PAYABLE_NAME, NameId.Type.Party.name(), supplierField.getValue(), supplierField.getName(), amountField.getUnitvalue(), 0.0, totalamount, descriptionField.getValue()); if (financeField.isVisible() && financeField.hasValue()) { post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), Account.ACCOUNTS_PAYABLE, Account.ACCOUNTS_PAYABLE_NAME, NameId.Type.Party.name(), supplierField.getValue(), supplierField.getName(), amountField.getUnitvalue(), totalamount, 0.0, descriptionField.getValue()); postFinance(true); } } /* * Post Journal - post a journal line item */ private void postJournal() { post(AbstractRoot.getOrganizationid(), AbstractRoot.getOrganizationname(), accountField.getValue(), accountField.getName(), accountField.hasValue(Account.FINANCE) ? NameId.Type.Finance.name() : NameId.Type.Party.name(), entityField.getValue(), entityField.getName(), // accountField.hasValue(Account.FINANCE) ? NameId.Type.Finance.name() : NameId.Type.Party.name(), // accountField.hasValue(Account.FINANCE) ? financeField.getValue() : entityField.getValue(), // accountField.hasValue(Account.FINANCE) ? financeField.getN() : entityField.getName(), amountField.getUnitvalue(), debitamountField.getValue(), creditamountField.getValue(), descriptionField.getValue()); } /* * Reservation Sale - post a sale for a reservation which includes entries for manager commission, * owner revenue and sales taxes where applicable. */ private final void postReservationSale() { Reservation reservation = reservationentities.getReservation(); Party supplier = reservationentities.getManager(); Party owner = reservationentities.getOwner(); Product product = reservationentities.getProduct(); if (reservationentities == null || supplier == null || owner == null || product == null) { Window.alert("JournalPopup postReservationSale " + (reservationentities == null) + "," + (supplier == null) + "," + (owner == null) + "," + (product == null)); } taxField.setName(Tax.VAT_NORMAL); //TODO: check Double taxrate = 0.0; try { taxrate = taxField.noValue() ? 0.0 : Double.valueOf(taxField.getValue()); } catch (NumberFormatException x) { AbstractField.addMessage(Level.ERROR, CONSTANTS.taxError() + taxField.getValue(), taxField); } boolean ownermanager = owner.hasId(supplier.getId()); Double supplieramount = Event.round(ownermanager ? amountField.getValue() : amountField.getValue() * product.getCommissionValue() / 100.0); Double suppliertax = Event .round(supplier.hasTaxnumber() ? taxrate * supplieramount / (100.0 + taxrate) : 0.0); Double suppliersale = supplieramount - suppliertax; Double owneramount = ownermanager ? 0.0 : amountField.getValue() - supplieramount; Double ownertax = Event.round(owner.hasTaxnumber() ? taxrate * owneramount / (100.0 + taxrate) : 0.0); Double ownersale = owneramount - ownertax; Double quantity = reservation.getDuration(Time.DAY); // CR Owner Sales post(owner.getId(), owner.getName(), Account.SALES_REVENUE, Account.SALES_REVENUE_NAME, NameId.Type.Product.name(), product.getId(), product.getName(), amountField.getUnitvalue(), 0.0, ownersale, quantity, Unit.DAY, descriptionField.getValue()); // CR Owner VAT post(owner.getId(), owner.getName(), Account.VAT_OUTPUT, Account.VAT_OUTPUT_NAME, null, null, null, amountField.getUnitvalue(), 0.0, ownertax, descriptionField.getValue()); // DR Owner Accounts Receivable post(owner.getId(), owner.getName(), Account.ACCOUNTS_RECEIVABLE, Account.ACCOUNTS_RECEIVABLE_NAME, NameId.Type.Party.name(), supplier.getId(), supplier.getName(), amountField.getUnitvalue(), ownersale + ownertax, 0.0, descriptionField.getValue()); // CR Manager Accounts Payable post(supplier.getId(), supplier.getName(), Account.ACCOUNTS_PAYABLE, Account.ACCOUNTS_PAYABLE_NAME, NameId.Type.Party.name(), owner.getId(), owner.getName(), amountField.getUnitvalue(), 0.0, ownersale + ownertax, descriptionField.getValue()); // CR Manager Sales post(supplier.getId(), supplier.getName(), Account.SALES_REVENUE, Account.SALES_REVENUE_NAME, NameId.Type.Product.name(), product.getId(), product.getName(), amountField.getUnitvalue(), 0.0, suppliersale, quantity, Unit.DAY, descriptionField.getValue()); // CR Manager VAT post(supplier.getId(), supplier.getName(), Account.VAT_OUTPUT, Account.VAT_OUTPUT_NAME, null, null, null, amountField.getUnitvalue(), 0.0, suppliertax, descriptionField.getValue()); // DR Manager Accounts Receivable from Customer post(supplier.getId(), supplier.getName(), Account.ACCOUNTS_RECEIVABLE, Account.ACCOUNTS_RECEIVABLE_NAME, NameId.Type.Party.name(), entityField.getValue(), //Agent if exists, else customer: STO for agent, Quote for Customer entityField.getName(), amountField.getUnitvalue(), ownersale + ownertax + suppliersale + suppliertax, 0.0, descriptionField.getValue()); } /* * Gets the currency exchange rate label to be displayed when the journal and finance currencies are not the same. * * @return the currency exchange rate label. */ private String getExchangeLabel() { return finance == null ? "" : CONSTANTS.exchangerateLabel() + amountField.getUnitvalue() + " - " + finance.getCurrency(); } /* Initializes the journal panel fields before they are used. */ private HorizontalPanel createContent() { HorizontalPanel panel = new HorizontalPanel(); VerticalPanel form = new VerticalPanel(); panel.add(form); reversedLabel = new Label(CONSTANTS.reversedLabel()); reversedLabel.addStyleName(CSS.reversedField()); form.add(reversedLabel); titleField = new Label(CONSTANTS.journalLabel()); titleField.addStyleName(AbstractField.CSS.cbtAbstractPopupLabel()); titleField.addStyleName(AbstractField.CSS.cbtAbstractPointer()); titleField.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (journalTable.noValue()) { reversed = !reversed; titleField.setText(reversed ? CONSTANTS.reversedNames()[type.ordinal()] : CONSTANTS.processNames()[type.ordinal()]); } } }); HorizontalPanel titlePanel = new HorizontalPanel(); titlePanel.add(titleField); reportButton = new Image(AbstractField.BUNDLE.printer()); reportButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { reportView.execute(); } }); reportButton.setTitle(AbstractField.CONSTANTS.helpPrinter()); titlePanel.add(reportButton); reportLoader = new Image(AbstractField.BUNDLE.loader()); reportLoader.setVisible(false); titlePanel.add(reportLoader); form.add(titlePanel); final Label closeButton = new Label(); closeButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { hide(); } }); closeButton.addStyleName(AbstractField.CSS.cbtAbstractPopupClose()); form.add(closeButton); //----------------------------------------------- // Process field //----------------------------------------------- processField = new ListField(this, null, NameId.getList(AbstractField.CONSTANTS.processList(), Event.PROCESSES), CONSTANTS.processLabel(), true, tab++); processField.setFieldHalf(); //form.add(processField); //----------------------------------------------- // Name field //----------------------------------------------- eventnameField = new SuggestField(this, null, new NameIdAction(Service.JOURNAL), CONSTANTS.eventnameLabel(), 20, tab++); eventnameField.setFieldHalf(); eventnameField.setHelpText(CONSTANTS.eventnameHelp()); form.add(eventnameField); //----------------------------------------------- // Date field which is the effective date of the transaction // It is not a timestamp of when the event was captured //----------------------------------------------- eventdateField = new DateField(this, null, CONSTANTS.eventdateLabel(), tab++); eventdateField.setHelpText(CONSTANTS.eventdateHelp()); form.add(eventdateField); //----------------------------------------------- // Tax Category field //----------------------------------------------- taxField = new ListField(this, null, new NameIdAction(Service.TAX), CONSTANTS.taxLabel(), false, tab++); taxField.setType(Tax.Type.SalesTaxIncluded.name()); taxField.setLabelStyle(CSS.taxLabel()); taxField.setFieldHalf(); taxField.setFieldStyle(CSS.taxField()); taxField.setHelpText(CONSTANTS.taxHelp()); form.add(taxField); //----------------------------------------------- // Finance field //----------------------------------------------- financeField = new ListField(this, null, new NameIdAction(Service.FINANCE), CONSTANTS.financeLabel(), true, tab++); financeField.setFieldStyle(CSS.financeField()); financeField.setVisible(false); financeField.setHelpText(CONSTANTS.financeHelp()); form.add(financeField); //----------------------------------------------- // Account field //----------------------------------------------- accountField = new SuggestField(this, null, new NameIdAction(Service.ACCOUNT), CONSTANTS.accountLabel(), 20, tab++); accountField.setType(Account.Type.Expense.name()); accountField.setVisible(false); accountField.setHelpText(CONSTANTS.accountHelp()); form.add(accountField); //----------------------------------------------- // Supplier field //----------------------------------------------- supplierField = new SuggestField(this, null, new NameIdAction(Service.PARTY), CONSTANTS.supplierLabel(), 20, tab++); Image supplierButton = new Image(AbstractField.BUNDLE.plus()); supplierButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { PartyPopup.getInstance().show(Party.Type.Customer, supplierField, null); } }); supplierButton.setTitle(CONSTANTS.partybuttonHelp()); supplierField.addButton(supplierButton); supplierField.setHelpText(CONSTANTS.supplierHelp()); form.add(supplierField); //----------------------------------------------- // Party field //----------------------------------------------- entityField = new SuggestField(this, null, new NameIdAction(Service.PARTY), CONSTANTS.subaccountLabels()[0], 20, tab++); entityField.setHelpText(CONSTANTS.partyHelp()); entityButton = new Image(AbstractField.BUNDLE.plus()); entityButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { PartyPopup.getInstance().show(partytypes[type.ordinal()], entityField, null); } }); entityButton.setTitle(CONSTANTS.partybuttonHelp()); entityField.addButton(entityButton); form.add(entityField); //----------------------------------------------- // Amount field //----------------------------------------------- amountField = new DoubleunitField(this, null, new CurrencyNameId(), CONSTANTS.amountLabel(), AbstractField.AF, tab++); amountField.setHelpText(CONSTANTS.amountHelp()); form.add(amountField); //----------------------------------------------- // Debit Amount field //----------------------------------------------- debitamountField = new DoubleField(this, null, CONSTANTS.debitamountLabel(), AbstractField.AF, tab++); debitamountField.setHelpText(CONSTANTS.debitamountHelp()); debitamountField.setVisible(false); //----------------------------------------------- // Credit Amount field //----------------------------------------------- creditamountField = new DoubleField(this, null, CONSTANTS.creditamountLabel(), AbstractField.AF, tab++); creditamountField.setVisible(false); creditamountField.setHelpText(CONSTANTS.creditamountHelp()); final HorizontalPanel dc = new HorizontalPanel(); dc.add(debitamountField); dc.add(creditamountField); form.add(dc); //----------------------------------------------- // Description field //----------------------------------------------- descriptionField = new TextAreaField(this, null, CONSTANTS.descriptionLabel(), tab++); descriptionField.setFieldStyle(CSS.descriptionField()); descriptionField.setMaxLength(1000); descriptionField.setHelpText(CONSTANTS.descriptionHelp()); form.add(descriptionField); //----------------------------------------------- // Exchange Rate field //----------------------------------------------- exchangerateField = new DoubleField(this, null, getExchangeLabel(), AbstractField.XF, tab++); exchangerateField.setVisible(false); exchangerateField.setHelpText(CONSTANTS.exchangerateHelp()); form.add(exchangerateField); //----------------------------------------------- // Logo field //----------------------------------------------- final Image paygate = new Image(AbstractField.BUNDLE.paygate()); final Image godaddy = new Image(AbstractField.BUNDLE.godaddy()); final Image thawte = new Image(AbstractField.BUNDLE.thawte()); final Image mastercard = new Image(AbstractField.BUNDLE.mastercard()); final Image visa = new Image(AbstractField.BUNDLE.visa()); logoImages = new HorizontalPanel(); logoImages.setTitle(CONSTANTS.logoLabel()); logoImages.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); logoImages.addStyleName(AbstractField.CSS.cbtAbstractPopupLabel()); logoImages.add(paygate); //logoImages.add(godaddy); logoImages.add(thawte); logoImages.add(mastercard); logoImages.add(visa); form.add(logoImages); //----------------------------------------------- // Card Holder field //----------------------------------------------- cardholderField = new TextField(this, null, CONSTANTS.cardholderLabel(), tab++); cardholderField.setVisible(false); cardholderField.setMaxLength(50); cardholderField.setHelpText(CONSTANTS.cardholderHelp()); form.add(cardholderField); //----------------------------------------------- // Card Number field //----------------------------------------------- cardnumberField = new TextField(this, null, CONSTANTS.cardnumberLabel(), tab++); cardnumberField.setVisible(false); cardnumberField.setHelpText(CONSTANTS.cardnumberHelp()); form.add(cardnumberField); //----------------------------------------------- // Card Expiry Month field //----------------------------------------------- cardmonthField = new ListField(this, null, Finance.getMonths(), null, false, tab++); cardmonthField.setVisible(false); carddetailLabel = new HelpLabel(CONSTANTS.carddetailLabel(), CONSTANTS.carddetailHelp(), cardmonthField); carddetailLabel.setVisible(false); form.add(carddetailLabel); cardmonthField.setFieldStyle(AbstractField.CSS.cbtListFieldCCmonth()); //----------------------------------------------- // Card Expiry Year field //----------------------------------------------- cardyearField = new ListField(this, null, Finance.getYears(), null, false, tab++); cardyearField.setVisible(false); cardyearField.setFieldStyle(AbstractField.CSS.cbtListFieldCCyear()); //----------------------------------------------- // Card Security Code field //----------------------------------------------- cardcodeField = new TextField(this, null, null, tab++); cardcodeField.setVisible(false); cardcodeField.setFieldStyle(AbstractField.CSS.cbtTextFieldCCcode()); HorizontalPanel ccc = new HorizontalPanel(); ccc.add(cardmonthField); ccc.add(cardyearField); ccc.add(cardcodeField); form.add(ccc); form.add(createCommands()); //----------------------------------------------- // Available selection change handler //----------------------------------------------- final NoSelectionModel<Journal> selectionModel = new NoSelectionModel<Journal>(); SelectionChangeEvent.Handler selectionHandler = new SelectionChangeEvent.Handler() { public void onSelectionChange(SelectionChangeEvent event) { selectedjournal = selectionModel.getLastSelectedObject(); setValue(selectedjournal); processField.setValue(Event.Type.Journal.name()); setView(); } }; selectionModel.addSelectionChangeHandler(selectionHandler); //----------------------------------------------- // Journal table //----------------------------------------------- journalTable = new TableField<Journal>(this, null, new JournalItemTable(), selectionModel, CONSTANTS.journaltableLabel(), JOURNAL_ROWS, tab++); journalTable.setLabelStyle(CSS.journaltableLabel()); journalTable.setVisible(false); int col = 0; //----------------------------------------------- // Organization column //----------------------------------------------- Column<Journal, String> organization = new Column<Journal, String>(new TextCell()) { @Override public String getValue(Journal journal) { return journal.getOrganizationname(); } }; journalTable.addStringColumn(organization, CONSTANTS.journalHeaders()[col++]); //----------------------------------------------- // Account column //----------------------------------------------- Column<Journal, String> process = new Column<Journal, String>(new TextCell()) { @Override public String getValue(Journal journal) { return journal.getAccountname(); } }; journalTable.addStringColumn(process, CONSTANTS.journalHeaders()[col++]); //----------------------------------------------- // Subaccount column //----------------------------------------------- Column<Journal, String> entityname = new Column<Journal, String>(new TextCell()) { @Override public String getValue(Journal journal) { return journal.getEntityname(); } }; journalTable.addStringColumn(entityname, CONSTANTS.journalHeaders()[col++]); //----------------------------------------------- // Debit column //----------------------------------------------- Column<Journal, Number> debitamount = new Column<Journal, Number>(new NumberCell(AbstractField.AF)) { @Override public Double getValue(Journal journal) { return journal.getDebitamount(); } }; journalTable.addNumberColumn(debitamount, CONSTANTS.journalHeaders()[col++]); //----------------------------------------------- // Credit column //----------------------------------------------- Column<Journal, Number> creditamount = new Column<Journal, Number>(new NumberCell(AbstractField.AF)) { @Override public Double getValue(Journal journal) { return journal.getCreditamount(); } }; journalTable.addNumberColumn(creditamount, CONSTANTS.journalHeaders()[col++]); //----------------------------------------------- // Currency column //----------------------------------------------- Column<Journal, String> currency = new Column<Journal, String>(new TextCell()) { @Override public String getValue(Journal journal) { return journal.getCurrency(); } }; journalTable.addStringColumn(currency, CONSTANTS.journalHeaders()[col++]); //----------------------------------------------- // Description column //----------------------------------------------- // Column<Journal, String> description = new Column<Journal, String>( new TextCell() ) { // @Override // public String getValue( Journal journal ) {return journal.getDescription();} // }; // journalTable.addStringColumn(description, CONSTANTS.journalHeaders()[col++]); panel.add(journalTable); onRefresh(); onReset(Event.CREATED); return panel; } /* Initializes the journal panel commands before they are used. */ private HorizontalPanel createCommands() { final HorizontalPanel bar = new HorizontalPanel(); bar.addStyleName(AbstractField.CSS.cbtAbstractCommand()); //----------------------------------------------- // Local action to cancel the journal //----------------------------------------------- LocalRequest cancelRequest = new LocalRequest() { protected String popup() { return hasChanged() ? AbstractField.CONSTANTS.errChangeOK() : null; } protected void perform() { hide(); } //nextFeature();} //TODO: hide();} }; //----------------------------------------------- // Local action to create a new line item for the journal //----------------------------------------------- LocalRequest itemRequest = new LocalRequest() { protected boolean error() { return (ifMessage(AbstractRoot.noOrganizationid(), Level.ERROR, AbstractField.CONSTANTS.errOrganizationid(), processField) || ifMessage(processField.noValue(), Level.ERROR, CONSTANTS.processError(), processField) || ifMessage(eventnameField.noValue(), Level.ERROR, AbstractField.CONSTANTS.errId(), eventnameField) || ifMessage(eventdateField.noValue(), Level.ERROR, AbstractField.CONSTANTS.errDate(), eventdateField) || ifMessage(processField.hasValue(Event.Type.Purchase.name()) && accountField.noValue(), Level.ERROR, CONSTANTS.accountError(), accountField) || ifMessage( (processField.hasValue(Event.Type.Payment.name()) || processField.hasValue(Event.Type.Receipt.name())) && financeField.noValue(), Level.ERROR, CONSTANTS.financeError(), financeField) || ifMessage(isParty() && entityField.noValue(), Level.ERROR, CONSTANTS.partyError(), entityField) || ifMessage(amountField.noValue(), Level.ERROR, CONSTANTS.amountError(), amountField) || ifMessage( (processField.hasValue(Event.Type.Payment.name()) || processField.hasValue(Event.Type.Receipt.name())) && !finance.hasCurrency(amountField.getUnitvalue()) && (exchangerateField.noValue() || exchangerateField.getValue() <= 0.01), Level.ERROR, CONSTANTS.exchangerateError(), financeField)); } protected void perform() { if (!error()) { boolean isJournal = processField.hasValue(Event.Type.Journal.name()); boolean isPayment = processField.hasValue(Event.Type.Payment.name()); boolean isPurchase = processField.hasValue(Event.Type.Purchase.name()); boolean isPurchaseSale = processField.hasValue(Event.Type.PurchaseSale.name()); boolean isReceipt = processField.hasValue(Event.Type.Receipt.name()); boolean isSale = processField.hasValue(Event.Type.Sale.name()); boolean isReservationSale = processField.hasValue(Event.Type.ReservationSale.name()); if (isPayment) { postPayment(true); } else if (isPurchase) { postPurchase(true); } else if (isPurchaseSale) { postPurchaseSale(); } else if (isReceipt) { postPayment(false); } else if (isSale) { postPurchase(false); } else if (isReservationSale) { postReservationSale(); } else { postJournal(); } accountField.setValue(null); Double balance = getBalance(); debitamountField.setValue(balance > 0.0 ? 0.0 : balance); creditamountField.setValue(balance < 0.0 ? 0.0 : balance); setView(); } } }; //----------------------------------------------- // Button to add a new line item to the journal //----------------------------------------------- itemButton = new CommandButton(this, CONSTANTS.itemLabel(), itemRequest, tab++); itemButton.addStyleName(AbstractField.CSS.cbtGradientGreen()); itemButton.setTitle(CONSTANTS.itemHelp()); bar.add(itemButton); //----------------------------------------------- // Button to save the journal to the database //----------------------------------------------- saveButton = new CommandButton(this, AbstractField.CONSTANTS.allSave(), journalUpdate, tab++); saveButton.addStyleName(AbstractField.CSS.cbtGradientBlue()); saveButton.setTitle(CONSTANTS.saveHelp()); bar.add(saveButton); //----------------------------------------------- // Button to submit a payment to the payment gateway //----------------------------------------------- submitButton = new Button(AbstractField.CONSTANTS.allSubmit()); submitButton.addStyleName(AbstractField.CSS.cbtCommandButton()); submitButton.addStyleName(AbstractField.CSS.cbtGradientGreen()); submitButton.setTitle(CONSTANTS.submitHelp()); submitButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (isCardPayment) { getJsonpPay(Currency.Code.USD.name()); } else if (isCardReceipt) { getJsonpReceive(Currency.Code.ZAR.name()); } } }); bar.add(submitButton); //----------------------------------------------- // Button to delete the journal from the database //----------------------------------------------- final CommandButton deleteButton = new CommandButton(this, AbstractField.CONSTANTS.allDelete(), journalDelete, tab++); deleteButton.addStyleName(AbstractField.CSS.cbtGradientRed()); deleteButton.setTitle(CONSTANTS.deleteHelp()); bar.add(deleteButton); //----------------------------------------------- // Button to cancel the current journal //----------------------------------------------- cancelButton = new CommandButton(this, AbstractField.CONSTANTS.allCancel(), cancelRequest, tab++); cancelButton.addStyleName(AbstractField.CSS.cbtGradientRed()); cancelButton.setTitle(CONSTANTS.cancelHelp()); bar.add(cancelButton); //----------------------------------------------- // Image to show a request to a service is in progress //----------------------------------------------- loader = new Image(AbstractField.BUNDLE.loader()); loader.setVisible(false); bar.add(loader); //----------------------------------------------- // Transition array to define this finite state machine. //----------------------------------------------- fsm = new ArrayList<Transition>(); fsm.add(new Transition(Event.INITIAL, itemButton, Event.INITIAL)); fsm.add(new Transition(Event.INITIAL, saveButton, Event.CREATED)); fsm.add(new Transition(Event.INITIAL, cancelButton, Event.CREATED)); fsm.add(new Transition(Event.CREATED, itemButton, Event.CREATED)); fsm.add(new Transition(Event.CREATED, saveButton, Event.CREATED)); fsm.add(new Transition(Event.CREATED, deleteButton, Event.CREATED)); return bar; } /* * Gets the current financial balance of the journal. * * @return the current financial balance. */ private Double getBalance() { if (journalTable == null || journalTable.noValue()) { return 0.0; } Double balance = 0.0; for (Journal journal : journalTable.getValue()) { balance += journal.getAmount(); } return balance; } /* * Checks if journal has an entity error. * * @return true if there is an entity error else false */ private boolean entityError() { if (journalTable.hasValue()) { for (Journal journal : journalTable.getValue()) { if (journal.entityError()) { return true; } } } return false; } /* Initializes the journal panel actions before they are used. */ private void createActions() { //----------------------------------------------- // Remote action to create a new journal instance. //----------------------------------------------- journalCreate = new GuardedRequest<Event<Journal>>() { protected boolean error() { return AbstractRoot.noOrganizationid(); } protected void send() { super.send(getValue(new JournalCreate())); } protected void receive(Event<Journal> event) { setValue(event); } }; //----------------------------------------------- // Remote action to read an existing journal instance. //----------------------------------------------- journalRead = new GuardedRequest<Event<Journal>>() { protected boolean error() { return eventnameField.noValue(); } protected void send() { super.send(getValue(new JournalRead())); } protected void receive(Event<Journal> event) { setValue(event); } }; //----------------------------------------------- // Remote action to update an existing journal instance. //----------------------------------------------- journalUpdate = new GuardedRequest<Event<Journal>>() { protected boolean error() { return (ifMessage(AbstractRoot.noOrganizationid(), Level.ERROR, AbstractField.CONSTANTS.errOrganizationid(), eventnameField) || ifMessage(AbstractRoot.noActorid(), Level.ERROR, AbstractField.CONSTANTS.errActorid(), eventnameField) || ifMessage(processField.noValue(), Level.ERROR, CONSTANTS.processError(), processField) || ifMessage(eventnameField.noValue(), Level.ERROR, AbstractField.CONSTANTS.errId(), eventnameField) || ifMessage(journalTable.noValue(), Level.ERROR, CONSTANTS.journaltableError(), processField) || ifMessage(financeField.isVisible() && financeField.hasValue(Finance.CBT_ZAR_FINANCE), Level.ERROR, CONSTANTS.gatewaynoZARError(), financeField) || ifMessage(entityError(), Level.ERROR, CONSTANTS.entityError(), eventnameField) || ifMessage(Math.abs(getBalance()) >= 0.01, Level.ERROR, CONSTANTS.balancedError() + AbstractField.AF.format(getBalance()), journalTable)); } protected void send() { super.send(getValue(new JournalUpdate())); } protected void receive(Event<Journal> event) { nextPrice(); } }; //----------------------------------------------- // Remote action to save an existing journal instance without checking its values. //----------------------------------------------- journalSave = new GuardedRequest<Event<Journal>>() { protected boolean error() { return false; } protected void send() { super.send(getValue(new JournalUpdate())); } protected void receive(Event<Journal> event) { if (parentField != null) { parentField.execute(true); } } }; //----------------------------------------------- // Remote action to delete an existing journal instance from the database. //----------------------------------------------- journalDelete = new GuardedRequest<Event<Journal>>() { protected String popup() { return AbstractField.CONSTANTS.errDeleteOK(); } protected boolean error() { return (ifMessage(eventnameField.noValue(), Level.ERROR, AbstractField.CONSTANTS.errId(), eventnameField) || ifMessage(isGateway(), Level.ERROR, CONSTANTS.gatewayError(), eventnameField)); } protected void send() { super.send(getValue(new JournalDelete())); } protected void receive(Event<Journal> event) { if (parentField != null) { parentField.execute(true); } hide(); } }; //----------------------------------------------- // Remote action to read an existing bank or cash account (finance) instance from the database. //----------------------------------------------- financeRead = new GuardedRequest<Finance>() { protected boolean error() { return financeField.noValue(); } protected void send() { super.send(getValue(new FinanceRead())); } protected void receive(Finance finance) { setValue(finance); } }; //----------------------------------------------- // Remote action to check if party is now licensed //----------------------------------------------- organizationLicense = new GuardedRequest<Party>() { protected boolean error() { return AbstractRoot.noOrganizationid(); } protected void send() { super.send(getValue(new PartyLicense())); } protected void receive(Party party) { } }; //----------------------------------------------- // Remote action to read the session organization instance from the database. //----------------------------------------------- organizationRead = new GuardedRequest<Party>() { protected boolean error() { return AbstractRoot.noOrganizationid(); } protected void send() { super.send(getValue(new PartyRead())); } protected void receive(Party party) { setValue(party); } }; //----------------------------------------------- // Remote action to create a printable report for this journal. //----------------------------------------------- reportView = new GuardedRequest<Report>() { protected boolean error() { return (getReport() == null || getReport().noDesign() || getReport().noNameRange()); } protected void send() { reportButton.setVisible(false); reportLoader.setVisible(true); super.send(getReport()); } public void receive(Report report) { reportLoader.setVisible(false); reportButton.setVisible(true); ReportPopup.getInstance().show(report); } }; //----------------------------------------------- // Read Guest Comments //----------------------------------------------- taxTable = new GuardedRequest<Table<Tax>>() { protected boolean error() { return false; } protected void send() { super.send(getValue(new TaxTable())); } protected void receive(Table<Tax> response) { taxes = response.getValue(); // Window.alert("taxes " + taxes); } }; } /* * Sends a JSONP payment request to the payment gateway. * * @param tocurrency the currency accepted by the payment gateway. */ private void getJsonpPay(String tocurrency) { if (ifMessage(AbstractRoot.noOrganizationid(), Level.ERROR, AbstractField.CONSTANTS.errOrganizationid(), processField) || ifMessage(AbstractRoot.noActorid(), Level.ERROR, AbstractField.CONSTANTS.errActorid(), processField) || ifMessage(processField.noValue(), Level.ERROR, CONSTANTS.processError(), processField) || ifMessage(eventnameField.noValue(), Level.ERROR, AbstractField.CONSTANTS.errId(), eventnameField) || ifMessage(!entityField.hasValue(Party.CBT_LTD_PARTY), Level.ERROR, CONSTANTS.gatewayCBTError(), entityField) || ifMessage(financeField.noValue(), Level.ERROR, CONSTANTS.financeError(), financeField) || ifMessage(amountField.noValue() || amountField.getValue() <= 0.0, Level.ERROR, CONSTANTS.amountError(), amountField) || ifMessage(cardholderField.noValue(), Level.ERROR, CONSTANTS.cardholderError(), cardholderField) || ifMessage(cardnumberField.noValue(), Level.ERROR, CONSTANTS.cardnumberError(), cardnumberField) || ifMessage(!Finance.isCreditCardNumber(cardnumberField.getValue()), Level.ERROR, CONSTANTS.cardnumberError(), cardnumberField) || ifMessage(cardmonthField.noValue(), Level.ERROR, CONSTANTS.cardmonthError(), cardmonthField) || ifMessage(cardyearField.noValue(), Level.ERROR, CONSTANTS.cardyearError(), cardyearField) || ifMessage(cardcodeField.noValue(), Level.ERROR, CONSTANTS.cardcodeError(), cardcodeField)) { return; } JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); String url = HOSTS.jsonUrl() + "?service=" + JSONRequest.PAY + "&pos=" + Window.Location.getParameter(AbstractRoot.Type.pos.name()) + "&organizationid=" + AbstractRoot.getOrganizationid() + "&financeid=" + financeField.getValue() + "&eventname=" + eventnameField.getValue() + "&amount=" + amountField.getValue() + "¤cy=" + amountField.getUnitvalue() + "&tocurrency=" + tocurrency + "&emailaddress=" + AbstractRoot.getSession().getEmailaddress() + "&cardholder=" + cardholderField.getValue() + "&cardnumber=" + cardnumberField.getValue() + "&cardmonth=" + cardmonthField.getValue() + "&cardyear=" + cardyearField.getValue() + "&cardcode=" + cardcodeField.getValue(); loader.setVisible(true); jsonp.requestObject(url, new AsyncCallback<PayWidgetItem>() { @Override public void onFailure(Throwable caught) { LoadingPopup.getInstance().hide(); loader.setVisible(false); throw new RuntimeException("getJsonpPay:" + caught.getMessage()); } @Override public void onSuccess(PayWidgetItem response) { loader.setVisible(false); message = response.getMessage(); if (response.getState().equalsIgnoreCase(RazorWidget.State.SUCCESS.name())) { finance.setCurrency(amountField.getUnitvalue()); finance.setOwnerid(AbstractRoot.getOrganizationid()); Double amount = Event.round(amountField.getValue() / response.getAmount(), 2); exchangerateField.setValue(amountField.getValue() / amount); amountField.setValue(amount); amountField.setUnitvalue(response.getCurrency()); postPayment(true); state = Event.CREATED; journalSave.execute(); setView(); submitButton.setVisible(false); cancelButton.setVisible(false); } else { AbstractField.addMessage(Level.ERROR, message, cardholderField); } } }); } /* * Sends a JSONP request to the payment gateway for a payment to be made to the licensor. * * @param tocurrency the currency accepted by the payment gateway. */ private void getJsonpReceive(String tocurrency) { if (ifMessage(AbstractRoot.noOrganizationid(), Level.ERROR, AbstractField.CONSTANTS.errOrganizationid(), processField) || ifMessage(AbstractRoot.noActorid(), Level.ERROR, AbstractField.CONSTANTS.errActorid(), processField) || ifMessage(processField.noValue(), Level.ERROR, CONSTANTS.processError(), processField) || ifMessage(eventnameField.noValue(), Level.ERROR, AbstractField.CONSTANTS.errId(), eventnameField) || ifMessage(!financeField.hasValue(Finance.CBT_ZAR_FINANCE), Level.ERROR, CONSTANTS.gatewayZARError(), financeField) || ifMessage(amountField.noValue() || amountField.getValue() <= 0.0, Level.ERROR, CONSTANTS.amountError(), amountField) || ifMessage(cardholderField.noValue(), Level.ERROR, CONSTANTS.cardholderError(), cardholderField) || ifMessage(cardnumberField.noValue(), Level.ERROR, CONSTANTS.cardnumberError(), cardnumberField) || ifMessage(!Finance.isCreditCardNumber(cardnumberField.getValue()), Level.ERROR, CONSTANTS.cardnumberError(), cardnumberField) || ifMessage(cardmonthField.noValue(), Level.ERROR, CONSTANTS.cardmonthError(), cardmonthField) || ifMessage(cardyearField.noValue(), Level.ERROR, CONSTANTS.cardyearError(), cardyearField) || ifMessage(cardcodeField.noValue(), Level.ERROR, CONSTANTS.cardcodeError(), cardcodeField)) { return; } JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); String url = HOSTS.jsonUrl() + "?service=" + JSONRequest.RECEIVE + "&pos=" + Window.Location.getParameter(AbstractRoot.Type.pos.name()) + "&organizationid=" + AbstractRoot.getOrganizationid() + "&financeid=" + financeField.getValue() + "&eventname=" + eventnameField.getValue() + "&amount=" + amountField.getValue() + "¤cy=" + amountField.getUnitvalue() + "&tocurrency=" + tocurrency + "&emailaddress=" + AbstractRoot.getSession().getEmailaddress() + "&cardholder=" + cardholderField.getValue() + "&cardnumber=" + cardnumberField.getValue() + "&cardmonth=" + cardmonthField.getValue() + "&cardyear=" + cardyearField.getValue() + "&cardcode=" + cardcodeField.getValue(); loader.setVisible(true); jsonp.requestObject(url, new AsyncCallback<PayWidgetItem>() { @Override public void onFailure(Throwable caught) { loader.setVisible(false); LoadingPopup.getInstance().hide(); throw new RuntimeException("getJsonpReceive:" + caught.getMessage()); } @Override public void onSuccess(PayWidgetItem response) { loader.setVisible(false); message = response.getMessage(); if (response.hasState(RazorWidget.State.SUCCESS.name())) { finance.setOwnerid(AbstractRoot.getOrganizationid()); postCardReceipt(); state = Event.CREATED; //TODO: FROZEN journalSave.execute(); setView(); submitButton.setVisible(false); cancelButton.setVisible(false); } else { AbstractField.addMessage(Level.ERROR, message, cardholderField); } } }); } /* Gets if the journal has a line item for the payment gateway. */ private static boolean isGateway() { for (Journal journal : journalTable.getValue()) { if (journal.isGateway()) { return true; } } return false; } }