/*
jBilling - The Enterprise Open Source Billing System
Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde
This file is part of jbilling.
jbilling is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jbilling 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with jbilling. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Created on Jan 27, 2005
* One session bean to expose as a single web service, thus, one wsdl
*/
package com.sapienter.jbilling.server.util;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import com.sapienter.jbilling.server.item.CurrencyBL;
import com.sapienter.jbilling.server.mediation.db.MediationRecordLineDAS;
import com.sapienter.jbilling.server.order.OrderHelper;
import com.sapienter.jbilling.server.user.contact.db.ContactDAS;
import com.sapienter.jbilling.server.user.ContactTypeWS;
import com.sapienter.jbilling.server.user.db.CompanyDAS;
import com.sapienter.jbilling.server.util.db.CurrencyDTO;
import com.sapienter.jbilling.server.util.db.LanguageDAS;
import com.sapienter.jbilling.server.util.db.LanguageDTO;
import com.sapienter.jbilling.server.util.db.PreferenceTypeDAS;
import com.sapienter.jbilling.server.util.db.PreferenceTypeDTO;
import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.sql.rowset.CachedRowSet;
import com.sapienter.jbilling.client.authentication.CompanyUserDetails;
import com.sapienter.jbilling.common.InvalidArgumentException;
import com.sapienter.jbilling.common.JBCrypto;
import com.sapienter.jbilling.common.SessionInternalError;
import com.sapienter.jbilling.server.invoice.IInvoiceSessionBean;
import com.sapienter.jbilling.server.invoice.InvoiceBL;
import com.sapienter.jbilling.server.invoice.InvoiceWS;
import com.sapienter.jbilling.server.invoice.db.InvoiceDAS;
import com.sapienter.jbilling.server.invoice.db.InvoiceDTO;
import com.sapienter.jbilling.server.item.IItemSessionBean;
import com.sapienter.jbilling.server.item.ItemBL;
import com.sapienter.jbilling.server.item.ItemDTOEx;
import com.sapienter.jbilling.server.item.ItemTypeBL;
import com.sapienter.jbilling.server.item.ItemTypeWS;
import com.sapienter.jbilling.server.item.PricingField;
import com.sapienter.jbilling.server.item.db.ItemDTO;
import com.sapienter.jbilling.server.item.db.ItemTypeDTO;
import com.sapienter.jbilling.server.mediation.IMediationSessionBean;
import com.sapienter.jbilling.server.mediation.MediationConfigurationBL;
import com.sapienter.jbilling.server.mediation.MediationConfigurationWS;
import com.sapienter.jbilling.server.mediation.MediationProcessWS;
import com.sapienter.jbilling.server.mediation.MediationRecordBL;
import com.sapienter.jbilling.server.mediation.MediationRecordLineWS;
import com.sapienter.jbilling.server.mediation.MediationRecordWS;
import com.sapienter.jbilling.server.mediation.Record;
import com.sapienter.jbilling.server.mediation.RecordCountWS;
import com.sapienter.jbilling.server.mediation.db.MediationConfiguration;
import com.sapienter.jbilling.server.mediation.db.MediationProcess;
import com.sapienter.jbilling.server.mediation.db.MediationRecordDAS;
import com.sapienter.jbilling.server.mediation.db.MediationRecordDTO;
import com.sapienter.jbilling.server.mediation.db.MediationRecordLineDTO;
import com.sapienter.jbilling.server.mediation.db.MediationRecordStatusDAS;
import com.sapienter.jbilling.server.mediation.db.MediationRecordStatusDTO;
import com.sapienter.jbilling.server.mediation.task.IMediationProcess;
import com.sapienter.jbilling.server.mediation.task.MediationResult;
import com.sapienter.jbilling.server.notification.INotificationSessionBean;
import com.sapienter.jbilling.server.notification.MessageDTO;
import com.sapienter.jbilling.server.notification.NotificationBL;
import com.sapienter.jbilling.server.order.IOrderSessionBean;
import com.sapienter.jbilling.server.order.OrderBL;
import com.sapienter.jbilling.server.order.OrderLineBL;
import com.sapienter.jbilling.server.order.OrderLineWS;
import com.sapienter.jbilling.server.order.OrderProcessWS;
import com.sapienter.jbilling.server.order.OrderWS;
import com.sapienter.jbilling.server.order.db.OrderDAS;
import com.sapienter.jbilling.server.order.db.OrderDTO;
import com.sapienter.jbilling.server.order.db.OrderLineDTO;
import com.sapienter.jbilling.server.order.db.OrderProcessDTO;
import com.sapienter.jbilling.server.user.contact.db.ContactDTO;
import com.sapienter.jbilling.server.user.contact.db.ContactTypeDAS;
import com.sapienter.jbilling.server.user.contact.db.ContactTypeDTO;
import com.sapienter.jbilling.server.util.db.PreferenceDTO;
import grails.plugins.springsecurity.SpringSecurityService;
import com.sapienter.jbilling.server.payment.IPaymentSessionBean;
import com.sapienter.jbilling.server.payment.PaymentAuthorizationDTOEx;
import com.sapienter.jbilling.server.payment.PaymentBL;
import com.sapienter.jbilling.server.payment.PaymentDTOEx;
import com.sapienter.jbilling.server.payment.PaymentWS;
import com.sapienter.jbilling.server.payment.db.PaymentDAS;
import com.sapienter.jbilling.server.payment.db.PaymentDTO;
import com.sapienter.jbilling.server.payment.db.PaymentMethodDAS;
import com.sapienter.jbilling.server.payment.db.PaymentMethodDTO;
import com.sapienter.jbilling.server.pluggableTask.TaskException;
import com.sapienter.jbilling.server.pluggableTask.admin.PluggableTaskBL;
import com.sapienter.jbilling.server.pluggableTask.admin.PluggableTaskDTO;
import com.sapienter.jbilling.server.pluggableTask.admin.PluggableTaskException;
import com.sapienter.jbilling.server.pluggableTask.admin.PluggableTaskManager;
import com.sapienter.jbilling.server.pluggableTask.admin.PluggableTaskWS;
import com.sapienter.jbilling.server.process.BillingProcessBL;
import com.sapienter.jbilling.server.process.BillingProcessConfigurationWS;
import com.sapienter.jbilling.server.process.BillingProcessDTOEx;
import com.sapienter.jbilling.server.process.BillingProcessWS;
import com.sapienter.jbilling.server.process.ConfigurationBL;
import com.sapienter.jbilling.server.process.IBillingProcessSessionBean;
import com.sapienter.jbilling.server.process.db.BillingProcessConfigurationDAS;
import com.sapienter.jbilling.server.process.db.BillingProcessConfigurationDTO;
import com.sapienter.jbilling.server.process.db.BillingProcessDTO;
import com.sapienter.jbilling.server.provisioning.IProvisioningProcessSessionBean;
import com.sapienter.jbilling.server.rule.task.IRulesGenerator;
import com.sapienter.jbilling.server.user.AchBL;
import com.sapienter.jbilling.server.user.ContactBL;
import com.sapienter.jbilling.server.user.ContactDTOEx;
import com.sapienter.jbilling.server.user.ContactWS;
import com.sapienter.jbilling.server.user.CreateResponseWS;
import com.sapienter.jbilling.server.user.CreditCardBL;
import com.sapienter.jbilling.server.user.IUserSessionBean;
import com.sapienter.jbilling.server.user.UserBL;
import com.sapienter.jbilling.server.user.UserDTOEx;
import com.sapienter.jbilling.server.user.UserTransitionResponseWS;
import com.sapienter.jbilling.server.user.UserWS;
import com.sapienter.jbilling.server.user.ValidatePurchaseWS;
import com.sapienter.jbilling.server.user.db.AchDTO;
import com.sapienter.jbilling.server.user.db.CompanyDTO;
import com.sapienter.jbilling.server.user.db.CreditCardDAS;
import com.sapienter.jbilling.server.user.db.CreditCardDTO;
import com.sapienter.jbilling.server.user.db.CustomerDAS;
import com.sapienter.jbilling.server.user.db.CustomerDTO;
import com.sapienter.jbilling.server.user.db.UserDAS;
import com.sapienter.jbilling.server.user.db.UserDTO;
import com.sapienter.jbilling.server.user.partner.PartnerBL;
import com.sapienter.jbilling.server.user.partner.PartnerWS;
import com.sapienter.jbilling.server.user.partner.db.Partner;
import com.sapienter.jbilling.server.util.api.WebServicesConstants;
import com.sapienter.jbilling.server.util.audit.EventLogger;
import com.sapienter.jbilling.server.util.db.CurrencyDAS;
import com.sapienter.jbilling.server.process.AgeingBL;
import com.sapienter.jbilling.server.process.AgeingDTOEx;
import com.sapienter.jbilling.server.process.AgeingWS;
import com.sapienter.jbilling.server.user.contact.db.ContactFieldTypeDTO;
import com.sapienter.jbilling.server.user.contact.db.ContactFieldTypeDAS;
import com.sapienter.jbilling.server.user.contact.ContactFieldTypeWS;
import com.sapienter.jbilling.server.order.OrderPeriodWS;
import com.sapienter.jbilling.server.order.db.OrderPeriodDTO;
import com.sapienter.jbilling.server.order.db.OrderPeriodDAS;
import com.sapienter.jbilling.server.user.CompanyWS;
import com.sapienter.jbilling.server.user.EntityBL;
import javax.naming.NamingException;
@Transactional( propagation = Propagation.REQUIRED )
public class WebServicesSessionSpringBean implements IWebServicesSessionBean {
private static final Logger LOG = Logger.getLogger(WebServicesSessionSpringBean.class);
private SpringSecurityService springSecurityService;
public SpringSecurityService getSpringSecurityService() {
if (springSecurityService == null)
this.springSecurityService = Context.getBean(Context.Name.SPRING_SECURITY_SERVICE);
return springSecurityService;
}
public void setSpringSecurityService(SpringSecurityService springSecurityService) {
this.springSecurityService = springSecurityService;
}
/*
* Returns the user ID of the authenticated user account making the web service call.
*
* @return caller user ID
*/
public Integer getCallerId() {
CompanyUserDetails details = (CompanyUserDetails) getSpringSecurityService().getPrincipal();
return details.getUserId();
}
/**
* Returns the company ID of the authenticated user account making the web service call.
*
* @return caller company ID
*/
public Integer getCallerCompanyId() {
CompanyUserDetails details = (CompanyUserDetails) getSpringSecurityService().getPrincipal();
return details.getCompanyId();
}
/**
* Returns the language ID of the authenticated user account making the web service call.
*
* @return caller language ID
*/
public Integer getCallerLanguageId() {
CompanyUserDetails details = (CompanyUserDetails) getSpringSecurityService().getPrincipal();
return details.getLanguageId();
}
// todo: reorganize methods and reformat code. should match the structure of the interface to make things readable.
/*
Invoices
*/
public InvoiceWS getInvoiceWS(Integer invoiceId)
throws SessionInternalError {
if (invoiceId == null) {
return null;
}
InvoiceDTO invoice = new InvoiceDAS().find(invoiceId);
if (invoice.getDeleted() == 1) {
return null;
}
InvoiceWS wsDto= InvoiceBL.getWS(invoice);
if ( null != invoice.getInvoiceStatus())
{
wsDto.setStatusDescr(invoice.getInvoiceStatus().getDescription(getCallerLanguageId()));
}
return wsDto;
}
public InvoiceWS[] getAllInvoicesForUser(Integer userId) {
IInvoiceSessionBean invoiceBean = Context.getBean(Context.Name.INVOICE_SESSION);
Set<InvoiceDTO> invoices = invoiceBean.getAllInvoices(userId);
List<InvoiceWS> ids = new ArrayList<InvoiceWS>(invoices.size());
for (InvoiceDTO invoice : invoices)
{
InvoiceWS wsdto= InvoiceBL.getWS(invoice);
if ( null != invoice.getInvoiceStatus())
wsdto.setStatusDescr(invoice.getInvoiceStatus().getDescription(getCallerLanguageId()));
ids.add(wsdto);
}
return ids.toArray(new InvoiceWS[ids.size()]);
}
public InvoiceWS[] getAllInvoices() {
List<InvoiceDTO> invoices = new InvoiceDAS().findAll();
List<InvoiceWS> ids = new ArrayList<InvoiceWS>(invoices.size());
for (InvoiceDTO invoice : invoices)
{
InvoiceWS wsdto= InvoiceBL.getWS(invoice);
if ( null != invoice.getInvoiceStatus())
wsdto.setStatusDescr(invoice.getInvoiceStatus().getDescription(getCallerLanguageId()));
ids.add(wsdto);
}
return ids.toArray(new InvoiceWS[ids.size()]);
}
public boolean notifyInvoiceByEmail(Integer invoiceId) {
INotificationSessionBean notificationSession =
(INotificationSessionBean) Context.getBean(
Context.Name.NOTIFICATION_SESSION);
return notificationSession.emailInvoice(invoiceId);
}
public boolean notifyPaymentByEmail(Integer paymentId) {
INotificationSessionBean notificationSession =
(INotificationSessionBean) Context.getBean(
Context.Name.NOTIFICATION_SESSION);
return notificationSession.emailPayment(paymentId);
}
public Integer[] getAllInvoices(Integer userId) {
IInvoiceSessionBean invoiceBean = Context.getBean(Context.Name.INVOICE_SESSION);
Set<InvoiceDTO> invoices = invoiceBean.getAllInvoices(userId);
List<Integer> ids = new ArrayList<Integer>(invoices.size());
for (InvoiceDTO invoice : invoices)
ids.add(invoice.getId());
return ids.toArray(new Integer[ids.size()]);
}
public InvoiceWS getLatestInvoice(Integer userId)
throws SessionInternalError {
InvoiceWS retValue = null;
try {
if (userId == null) {
return null;
}
InvoiceBL bl = new InvoiceBL();
Integer invoiceId = bl.getLastByUser(userId);
if (invoiceId != null) {
retValue = bl.getWS(new InvoiceDAS().find(invoiceId));
}
return retValue;
} catch (Exception e) { // needed because the sql exception :(
LOG.error("Exception in web service: getting latest invoice" +
" for user " + userId, e);
throw new SessionInternalError("Error getting latest invoice");
}
}
public Integer[] getLastInvoices(Integer userId, Integer number)
throws SessionInternalError {
if (userId == null || number == null) {
return null;
}
InvoiceBL bl = new InvoiceBL();
return bl.getManyWS(userId, number);
}
public Integer[] getInvoicesByDate(String since, String until)
throws SessionInternalError {
try {
Date dSince = com.sapienter.jbilling.common.Util.parseDate(since);
Date dUntil = com.sapienter.jbilling.common.Util.parseDate(until);
if (since == null || until == null) {
return null;
}
Integer entityId = getCallerCompanyId();
InvoiceBL invoiceBl = new InvoiceBL();
return invoiceBl.getInvoicesByCreateDateArray(entityId, dSince, dUntil);
} catch (Exception e) { // needed for the SQLException :(
LOG.error("Exception in web service: getting invoices by date" +
since + until, e);
throw new SessionInternalError("Error getting last invoices");
}
}
/**
* Returns the invoices for the user within the given date range.
*/
public Integer[] getUserInvoicesByDate(Integer userId, String since,
String until) throws SessionInternalError {
if (userId == null || since == null || until == null) {
return null;
}
Date dSince = com.sapienter.jbilling.common.Util.parseDate(since);
Date dUntil = com.sapienter.jbilling.common.Util.parseDate(until);
InvoiceBL invoiceBl = new InvoiceBL();
Integer[] results = invoiceBl.getUserInvoicesByDate(userId, dSince,
dUntil);
return results;
}
/**
* Returns an array of IDs for all unpaid invoices under the given user ID.
*
* @param userId user IDs
* @return array of un-paid invoice IDs
*/
public Integer[] getUnpaidInvoices(Integer userId) {
try {
CachedRowSet rs = new InvoiceBL().getPayableInvoicesByUser(userId);
Integer[] invoiceIds = new Integer[rs.size()];
int i = 0;
while (rs.next())
invoiceIds[i++] = rs.getInt(1);
rs.close();
return invoiceIds;
} catch (SQLException e) {
throw new SessionInternalError("Exception occurred querying payable invoices.");
} catch (Exception e) {
throw new SessionInternalError("An un-handled exception occurred querying payable invoices.");
}
}
/**
* Generates and returns the paper invoice PDF for the given invoiceId.
*
* @param invoiceId invoice to generate PDF for
* @return PDF invoice bytes
* @throws SessionInternalError
*/
public byte[] getPaperInvoicePDF(Integer invoiceId) throws SessionInternalError {
IInvoiceSessionBean invoiceSession = (IInvoiceSessionBean) Context.getBean(Context.Name.INVOICE_SESSION);
return invoiceSession.getPDFInvoice(invoiceId);
}
/**
* Un-links a payment from an invoice, effectivley making the invoice "unpaid" by
* removing the payment balance.
*
* If either invoiceId or paymentId parameters are null, no operation will be performed.
*
* @param invoiceId target Invoice
* @param paymentId payment to be unlink
*/
public void removePaymentLink(Integer invoiceId, Integer paymentId) {
if (invoiceId == null || paymentId == null)
return;
boolean result= new PaymentBL(paymentId).unLinkFromInvoice(invoiceId);
if (!result)
throw new SessionInternalError("Unable to find the Invoice Id " + invoiceId + " linked to Payment Id " + paymentId);
}
/**
* Applies an existing payment to an invoice.
*
* If either invoiceId or paymentId parameters are null, no operation will be performed.
*
* @param invoiceId target invoice
* @param paymentId payment to apply
*/
public void createPaymentLink(Integer invoiceId, Integer paymentId) {
IPaymentSessionBean session = Context.getBean(Context.Name.PAYMENT_SESSION);
session.applyPayment(paymentId, invoiceId);
}
/**
* Deletes an invoice
* @param invoiceId
* The id of the invoice to delete
*/
public void deleteInvoice(Integer invoiceId) {
Integer executorId = getCallerId();
InvoiceBL invoice = new InvoiceBL(invoiceId);
invoice.delete(executorId);
}
/**
* Deletes an Item
* @param itemId
* The id of the item to delete
*/
public void deleteItem(Integer itemId) throws SessionInternalError {
ItemBL itemBl= new ItemBL(itemId);
itemBl.delete(getCallerId());
LOG.debug("Deleted Item, " + itemBl.getEntity().getDeleted());
}
/**
* Deletes an Item Category
* @param itemCategoryId
* The id of the Item Category to delete
*/
public void deleteItemCategory(Integer itemCategoryId) throws SessionInternalError {
ItemTypeBL bl = new ItemTypeBL(itemCategoryId);
bl.delete(getCallerId());
}
/**
* Generates invoices for orders not yet invoiced for this user.
* Optionally only allow recurring orders to generate invoices.
* Returns the ids of the invoices generated.
*/
public Integer[] createInvoice(Integer userId, boolean onlyRecurring)
throws SessionInternalError {
UserDTO user = new UserDAS().find(userId);
BillingProcessBL processBL = new BillingProcessBL();
BillingProcessConfigurationDTO config =
new BillingProcessConfigurationDAS().findByEntity(
user.getCompany());
// Create a mock billing process object, because the method
// we are calling was meant to be called by the billing process.
BillingProcessDTO billingProcess = new BillingProcessDTO();
billingProcess.setId(0);
billingProcess.setEntity(user.getCompany());
billingProcess.setBillingDate(new Date());
billingProcess.setPeriodUnit(config.getPeriodUnit());
billingProcess.setPeriodValue(config.getPeriodValue());
billingProcess.setIsReview(0);
billingProcess.setRetriesToDo(0);
InvoiceDTO[] newInvoices = processBL.generateInvoice(billingProcess,
user, false, onlyRecurring);
if (newInvoices != null) {
Integer[] invoiceIds = new Integer[newInvoices.length];
for (int i = 0; i < newInvoices.length; i++) {
invoiceIds[i] = newInvoices[i].getId();
}
return invoiceIds;
} else {
return new Integer[]{};
}
}
/**
* Generates a new invoice for an order, or adds the order to an
* existing invoice.
*
* @param orderId order id to generate an invoice for
* @param invoiceId optional invoice id to add the order to. If null, a new invoice will be created.
* @return id of generated invoice, null if no invoice generated.
* @throws SessionInternalError if user id or order id is null.
*/
public Integer createInvoiceFromOrder(Integer orderId, Integer invoiceId) throws SessionInternalError {
if (orderId == null) throw new SessionInternalError("Order id cannot be null.");
// validate order to be processed
OrderDTO order = new OrderDAS().find(orderId);
if (order == null || !Constants.ORDER_STATUS_ACTIVE.equals(order.getStatusId())) {
LOG.debug("Order must exist and be active to generate an invoice.");
return null;
}
// create new invoice, or add to an existing invoice
InvoiceDTO invoice;
if (invoiceId == null) {
LOG.debug("Creating a new invoice for order " + order.getId());
invoice = doCreateInvoice(order.getId());
if ( null == invoice) {
throw new SessionInternalError("Invoice could not be generated. The purchase order may not have any applicable periods to be invoiced.");
}
} else {
LOG.debug("Adding order " + order.getId() + " to invoice " + invoiceId);
IBillingProcessSessionBean process = (IBillingProcessSessionBean) Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
invoice = process.generateInvoice(order.getId(), invoiceId, null);
}
return invoice == null ? null : invoice.getId();
}
/*
* USERS
*/
/**
* Creates a new user. The user to be created has to be of the roles customer
* or partner.
* The username has to be unique, otherwise the creating won't go through. If
* that is the case, the return value will be null.
* @param newUser
* The user object with all the information of the new user. If contact or
* credit card information are present, they will be included in the creation
* although they are not mandatory.
* @return The id of the new user, or null if non was created
*/
public Integer createUser(UserWS newUser)
throws SessionInternalError {
// validateUser(newUser);
newUser.setUserId(0);
Integer entityId = getCallerCompanyId();
UserBL bl = new UserBL();
if (bl.exists(newUser.getUserName(), entityId)) {
throw new SessionInternalError("User already exists with username " + newUser.getUserName(),
new String[] { "UserWS,userName,validation.error.user.already.exists" });
}
ContactBL cBl = new ContactBL();
UserDTOEx dto = new UserDTOEx(newUser, entityId);
Integer userId = bl.create(dto);
if (newUser.getContact() != null) {
newUser.getContact().setId(0);
cBl.createPrimaryForUser(new ContactDTOEx(newUser.getContact()), userId, entityId);
}
if (newUser.getCreditCard() != null) {
CreditCardDTO card = new CreditCardDTO(newUser.getCreditCard()); // new CreditCardDTO
card.setId(0);
card.getBaseUsers().add(bl.getEntity());
CreditCardBL ccBL = new CreditCardBL();
ccBL.create(card);
UserDTO userD = new UserDAS().find(userId);
userD.getCreditCards().add(ccBL.getEntity());
}
if (newUser.getAch() != null) {
AchDTO ach = new AchDTO(newUser.getAch());
ach.setId(0);
ach.setBaseUser(bl.getEntity());
AchBL abl = new AchBL();
abl.create(ach);
}
return userId;
}
public void deleteUser(Integer userId) throws SessionInternalError {
UserBL bl = new UserBL();
Integer executorId = getCallerId();
bl.set(userId);
bl.delete(executorId);
}
/**
* Fetches the ContactTypeWS for the given contact type ID. The returned WS object
* contains a list of international descriptions for all available languages.
*
* @param contactTypeId contact type ID
* @return contact type WS object
* @throws SessionInternalError
*/
public ContactTypeWS getContactTypeWS(Integer contactTypeId) throws SessionInternalError {
ContactTypeDTO contactType = new ContactTypeDAS().find(contactTypeId);
List<LanguageDTO> languages = new LanguageDAS().findAll();
return new ContactTypeWS(contactType, languages);
}
/**
* Creates a new contact type from the given WS object. This method also stores the international
* description for each description/language in the WS object.
*
* @param contactType contact type WS
* @return ID of created contact type
* @throws SessionInternalError
*/
public Integer createContactTypeWS(ContactTypeWS contactType) throws SessionInternalError {
ContactTypeDTO dto = new ContactTypeDTO();
dto.setEntity(new CompanyDTO(getCallerCompanyId()));
dto.setIsPrimary(contactType.getPrimary());
ContactTypeDAS contactTypeDas = new ContactTypeDAS();
dto = contactTypeDas.save(dto);
for (InternationalDescriptionWS description : contactType.getDescriptions()) {
dto.setDescription(description.getContent(), description.getLanguageId());
}
// flush changes to the DB & clear cache
contactTypeDas.flush();
contactTypeDas.clear();
return dto.getId();
}
public void updateUserContact(Integer userId, Integer typeId, ContactWS contact) throws SessionInternalError {
// todo: support multiple WS method param validations through WSSecurityMethodMapper
ContactTypeDTO type = new ContactTypeDAS().find(typeId);
if (type == null || type.getEntity() == null || !getCallerCompanyId().equals(type.getEntity().getId()))
throw new SessionInternalError("Invalid contact type.");
// update the contact
ContactBL cBl = new ContactBL();
cBl.updateForUser(new ContactDTOEx(contact), userId, typeId);
}
/**
* @param user
*/
public void updateUser(UserWS user)
throws SessionInternalError {
//TODO commenting validate user for create/edit customer grails impl. - vikasb
//validateUser(user);
UserBL bl = new UserBL(user.getUserId());
// get the entity
Integer entityId = getCallerCompanyId();
Integer executorId = getCallerId();
// convert to a DTO
UserDTOEx dto = new UserDTOEx(user, entityId);
// update the user info
bl.update(executorId, dto);
// now update the contact info
if (user.getContact() != null) {
ContactBL contactBl = new ContactBL();
contactBl.setEntity(entityId);
contactBl.createUpdatePrimaryForUser(new ContactDTOEx(user.getContact()), user.getUserId(), entityId);
}
// and the credit card
if (user.getCreditCard() != null) {
IUserSessionBean sess = (IUserSessionBean) Context.getBean(
Context.Name.USER_SESSION);
sess.updateCreditCard(executorId, user.getUserId(),
new CreditCardDTO(user.getCreditCard()));
}
//udpate customerdto here - notes, automaticPaymentMethod
CustomerDTO cust= UserBL.getUserEntity(user.getUserId()).getCustomer();
if ( null != cust ) {
LOG.debug("This code should save=" + user.getNotes() + " and " + user.getAutomaticPaymentType());
cust.setNotes(user.getNotes());
cust.setAutoPaymentType(user.getAutomaticPaymentType());
new CustomerDAS().save(cust);
}
}
/**
* Retrieves a user with its contact and credit card information.
* @param userId
* The id of the user to be returned
*/
public UserWS getUserWS(Integer userId) throws SessionInternalError {
UserBL bl = new UserBL(userId);
return bl.getUserWS();
}
/**
* Retrieves all the contacts of a user
* @param userId
* The id of the user to be returned
*/
public ContactWS[] getUserContactsWS(Integer userId)
throws SessionInternalError {
ContactWS[] dtos = null;
ContactBL contact = new ContactBL();
List result = contact.getAll(userId);
dtos = new ContactWS[result.size()];
for (int f = 0; f < result.size(); f++) {
dtos[f] = new ContactWS((ContactDTOEx) result.get(f));
}
return dtos;
}
/**
* Retrieves the user id for the given username
*/
public Integer getUserId(String username)
throws SessionInternalError {
UserDAS das = new UserDAS();
Integer retValue = das.findByUserName(username,
getCallerCompanyId()).getId();
return retValue;
}
/**
* Retrieves an array of users in the required status
*/
public Integer[] getUsersInStatus(Integer statusId) throws SessionInternalError {
return getUsersByStatus(statusId, true);
}
/**
* Retrieves an array of users in the required status
*/
public Integer[] getUsersNotInStatus(Integer statusId) throws SessionInternalError {
return getUsersByStatus(statusId, false);
}
/**
* Retrieves an array of users in the required status
*/
public Integer[] getUsersByCustomField(Integer typeId, String value)
throws SessionInternalError {
try {
UserBL bl = new UserBL();
Integer entityId = getCallerCompanyId();
CachedRowSet users = bl.getByCustomField(entityId, typeId, value);
LOG.debug("got collection. Now converting");
Integer[] ret = new Integer[users.size()];
int f = 0;
while (users.next()) {
ret[f] = users.getInt(1);
f++;
}
users.close();
return ret;
} catch (Exception e) { // can't remove because of the SQL Exception :(
LOG.error("WS - getUsersByCustomField", e);
throw new SessionInternalError("Error getting users by custom field");
}
}
public void saveCustomContactFields(ContactFieldTypeWS[] fields) throws SessionInternalError {
try {
ContactFieldTypeDAS das= new ContactFieldTypeDAS();
for (ContactFieldTypeWS ws: fields) {
ContactFieldTypeDTO dto= ws.getId() == null ? new ContactFieldTypeDTO() : das.find(ws.getId());
dto.setDataType(ws.getDataType());
dto.setReadOnly(ws.getReadOnly());
dto.setPromptKey("placeholder_text");
dto.setEntity(new CompanyDTO(ws.getCompanyId()));
dto.setVersionNum(new Integer(0));
dto= das.save(dto);
for (InternationalDescriptionWS description : ws.getDescriptions()) {
dto.setDescription(description.getContent(), description.getLanguageId());
}
das.flush();
das.clear();
}
}catch (Exception e) {
throw new SessionInternalError(e);
}
}
@Deprecated
private Integer[] getByCCNumber(Integer entityId, String number) {
List<Integer> usersIds = new CreditCardDAS().findByLastDigits(entityId, number);
Integer[] ids = new Integer[usersIds.size()];
return usersIds.toArray(ids);
}
/**
* Retrieves an array of users in the required status
*/
public Integer[] getUsersByCreditCard(String number) throws SessionInternalError {
Integer entityId = getCallerCompanyId();
Integer[] ret = getByCCNumber(entityId, number);
return ret;
}
/**
* Retrieves an array of users in the required status
*/
public Integer[] getUsersByStatus(Integer statusId, boolean in) throws SessionInternalError {
try {
UserBL bl = new UserBL();
CachedRowSet users = bl.getByStatus(getCallerCompanyId(), statusId, in);
LOG.debug("got collection. Now converting");
Integer[] ret = new Integer[users.size()];
int f = 0;
while (users.next()) {
ret[f] = users.getInt(1);
f++;
}
users.close();
return ret;
} catch (Exception e) { // can't remove because of SQLException :(
throw new SessionInternalError(e);
}
}
/**
* Creates a user, then an order for it, an invoice out the order
* and tries the invoice to be paid by an online payment
* This is ... the mega call !!!
*/
public CreateResponseWS create(UserWS user, OrderWS order)
throws SessionInternalError {
CreateResponseWS retValue = new CreateResponseWS();
// the user first
final Integer userId = createUser(user);
retValue.setUserId(userId);
if (userId == null) {
return retValue;
}
// the order and (if needed) invoice
order.setUserId(userId);
Integer orderId = doCreateOrder(order, true).getId();
InvoiceDTO invoice = doCreateInvoice(orderId);
retValue.setOrderId(orderId);
if (invoice != null) {
retValue.setInvoiceId(invoice.getId());
//the payment, if we have a credit card
if (user.getCreditCard() != null) {
PaymentDTOEx payment = doPayInvoice(invoice, new CreditCardDTO(user.getCreditCard()));
PaymentAuthorizationDTOEx result = null;
if (payment != null) {
result = new PaymentAuthorizationDTOEx(payment.getAuthorization().getOldDTO());
result.setResult(new Integer(payment.getPaymentResult().getId()).equals(Constants.RESULT_OK));
}
retValue.setPaymentResult(result);
retValue.setPaymentId(payment.getId());
}
} else {
throw new SessionInternalError("Invoice expected for order: " + orderId);
}
return retValue;
}
public void processPartnerPayouts(Date runDate) {
IUserSessionBean userSession = Context.getBean(Context.Name.USER_SESSION);
userSession.processPayouts(runDate);
}
public PartnerWS getPartner(Integer partnerId) throws SessionInternalError {
IUserSessionBean userSession = Context.getBean(Context.Name.USER_SESSION);
Partner dto = userSession.getPartnerDTO(partnerId);
return PartnerBL.getWS(dto);
}
/**
* Pays given invoice, using the first credit card available for invoice'd
* user.
*
* @return <code>null</code> if invoice has not positive balance, or if
* user does not have credit card
* @return resulting authorization record. The payment itself can be found by
* calling getLatestPayment
*/
public PaymentAuthorizationDTOEx payInvoice(Integer invoiceId) throws SessionInternalError {
if (invoiceId == null) {
throw new SessionInternalError("Can not pay null invoice");
}
final InvoiceDTO invoice = findInvoice(invoiceId);
CreditCardDTO creditCard = getCreditCard(invoice.getBaseUser().getUserId());
if (creditCard == null) {
return null;
}
PaymentDTOEx payment = doPayInvoice(invoice, creditCard);
PaymentAuthorizationDTOEx result = null;
if (payment != null) {
result = new PaymentAuthorizationDTOEx(payment.getAuthorization().getOldDTO());
result.setResult(new Integer(payment.getPaymentResult().getId()).equals(Constants.RESULT_OK));
}
return result;
}
/*
* ORDERS
*/
/**
* @return the information of the payment aurhotization, or NULL if the
* user does not have a credit card
*/
public PaymentAuthorizationDTOEx createOrderPreAuthorize(OrderWS order)
throws SessionInternalError {
PaymentAuthorizationDTOEx retValue = null;
// start by creating the order. It'll do the checks as well
Integer orderId = createOrder(order);
Integer userId = order.getUserId();
CreditCardDTO cc = getCreditCard(userId);
UserBL user = new UserBL();
Integer entityId = user.getEntityId(userId);
if (cc != null) {
CreditCardBL ccBl = new CreditCardBL();
OrderDAS das = new OrderDAS();
OrderDTO dbOrder = das.find(orderId);
try {
retValue = ccBl.validatePreAuthorization(entityId, userId, cc, dbOrder.getTotal(), dbOrder.getCurrencyId());
} catch (PluggableTaskException e) {
throw new SessionInternalError("doing validation", WebServicesSessionSpringBean.class, e);
}
}
return retValue;
}
public Integer createOrder(OrderWS order)
throws SessionInternalError {
Integer orderId = doCreateOrder(order, true).getId();
return orderId;
}
/**
* Update the given order, or create it if it doesn't already exist.
*
* @param order order to update or create
* @return order id
* @throws SessionInternalError
*/
public Integer createUpdateOrder(OrderWS order) throws SessionInternalError {
IOrderSessionBean orderSession = Context.getBean(Context.Name.ORDER_SESSION);
OrderDTO dto = new OrderBL().getDTO(order);
return orderSession.createUpdate(getCallerCompanyId(), getCallerId(), dto, getCallerLanguageId());
}
public OrderWS rateOrder(OrderWS order)
throws SessionInternalError {
OrderWS ordr = doCreateOrder(order, false);
return ordr;
}
public OrderWS[] rateOrders(OrderWS orders[])
throws SessionInternalError {
if (orders == null || orders.length == 0) {
LOG.debug("Call to rateOrders without orders to rate");
return null;
}
OrderWS retValue[] = new OrderWS[orders.length];
for (int index = 0; index < orders.length; index++) {
retValue[index] = doCreateOrder(orders[index],false);
}
return retValue;
}
public void updateItem(ItemDTOEx item) {
UserBL bl = new UserBL(getCallerId());
Integer executorId = bl.getEntity().getUserId();
Integer languageId = bl.getEntity().getLanguageIdField();
// do some transformation from WS to DTO :(
ItemBL itemBL = new ItemBL();
ItemDTO dto = itemBL.getDTO(item);
IItemSessionBean itemSession = (IItemSessionBean) Context.getBean(
Context.Name.ITEM_SESSION);
itemSession.update(executorId, dto, languageId);
}
/**
* Creates the given Order in jBilling, generates an Invoice for the same.
* Returns the generated Invoice ID
*/
public Integer createOrderAndInvoice(OrderWS order)
throws SessionInternalError {
Integer orderId = doCreateOrder(order, true).getId();
InvoiceDTO invoice = doCreateInvoice(orderId);
return invoice == null ? null : invoice.getId();
}
private void processLines(OrderDTO order, Integer languageId, Integer entityId, Integer userId, Integer currencyId,
String pricingFields) throws SessionInternalError {
OrderHelper.synchronizeOrderLines(order);
for (OrderLineDTO line : order.getLines()) {
LOG.debug("Processing line " + line);
if (line.getUseItem()) {
List<PricingField> fields = pricingFields != null
? Arrays.asList(PricingField.getPricingFieldsValue(pricingFields))
: null;
ItemBL itemBl = new ItemBL(line.getItemId());
itemBl.setPricingFields(fields);
// get item with calculated price
ItemDTO item = itemBl.getDTO(languageId, userId, entityId, currencyId, line.getQuantity(), order);
LOG.debug("Populating line using item " + item);
// set price or percentage from item
if (item.getPrice() == null) {
line.setPrice(item.getPercentage());
} else {
line.setPrice(item.getPrice());
}
// set description and line type
line.setDescription(item.getDescription());
line.setTypeId(item.getOrderLineTypeId());
}
}
OrderHelper.desynchronizeOrderLines(order);
}
public void updateOrder(OrderWS order)
throws SessionInternalError {
validateOrder(order);
try {
// start by locking the order
OrderBL oldOrder = new OrderBL();
oldOrder.setForUpdate(order.getId());
// do some transformation from WS to DTO :(
OrderBL orderBL = new OrderBL();
OrderDTO dto = orderBL.getDTO(order);
// get the info from the caller
UserBL bl = new UserBL(getCallerId());
Integer executorId = bl.getEntity().getUserId();
Integer entityId = bl.getEntityId(bl.getEntity().getUserId());
Integer languageId = bl.getEntity().getLanguageIdField();
// see if the related items should provide info
processLines(dto, languageId, entityId, order.getUserId(), order.getCurrencyId(), order.getPricingFields());
// recalculate
orderBL.set(dto);
orderBL.recalculate(entityId);
// update
oldOrder.update(executorId, dto);
} catch (Exception e) {
LOG.error("WS - updateOrder", e);
throw new SessionInternalError("Error updating order");
}
}
public OrderWS getOrder(Integer orderId) throws SessionInternalError {
// get the info from the caller
UserBL userbl = new UserBL(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
// now get the order. Avoid the proxy since this is for the client
OrderDAS das = new OrderDAS();
OrderDTO order = das.findNow(orderId);
if (order == null) { // not found
return null;
}
OrderBL bl = new OrderBL(order);
if (order.getDeleted() == 1) {
LOG.debug("Returning deleted order " + orderId);
}
return bl.getWS(languageId);
}
public Integer[] getOrderByPeriod(Integer userId, Integer periodId)
throws SessionInternalError {
if (userId == null || periodId == null) {
return null;
}
// now get the order
OrderBL bl = new OrderBL();
return bl.getByUserAndPeriod(userId, periodId);
}
public OrderLineWS getOrderLine(Integer orderLineId) throws SessionInternalError {
// now get the order
OrderBL bl = new OrderBL();
OrderLineWS retValue = null;
retValue = bl.getOrderLineWS(orderLineId);
return retValue;
}
public void updateOrderLine(OrderLineWS line) throws SessionInternalError {
// now get the order
OrderBL bl = new OrderBL();
bl.updateOrderLine(line);
}
public OrderWS getLatestOrder(Integer userId) throws SessionInternalError {
if (userId == null) {
throw new SessionInternalError("User id can not be null");
}
OrderWS retValue = null;
// get the info from the caller
UserBL userbl = new UserBL(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
// now get the order
OrderBL bl = new OrderBL();
Integer orderId = bl.getLatest(userId);
if (orderId != null) {
bl.set(orderId);
retValue = bl.getWS(languageId);
}
return retValue;
}
public Integer[] getLastOrders(Integer userId, Integer number)
throws SessionInternalError {
if (userId == null || number == null) {
return null;
}
UserBL userbl = new UserBL();
OrderBL order = new OrderBL();
return order.getListIds(userId, number, userbl.getEntityId(userId));
}
public void deleteOrder(Integer id) throws SessionInternalError {
// now get the order
OrderBL bl = new OrderBL();
bl.setForUpdate(id);
bl.delete(getCallerId());
}
/**
* Returns the current order (order collecting current one-time charges) for the
* period of the given date and the given user.
* Returns null for users with no main subscription order.
*/
public OrderWS getCurrentOrder(Integer userId, Date date) {
OrderWS retValue = null;
// get the info from the caller
UserBL userbl = new UserBL(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
// now get the current order
OrderBL bl = new OrderBL();
if (bl.getCurrentOrder(userId, date) != null) {
retValue = bl.getWS(languageId);
}
return retValue;
}
/**
* Updates the uesr's current one-time order for the given date.
* Returns the updated current order. Throws an exception for
* users with no main subscription order.
*/
public OrderWS updateCurrentOrder(Integer userId, OrderLineWS[] lines,
String pricing, Date date, String eventDescription) {
try {
UserBL userbl = new UserBL(userId);
// check user has a main subscription order
if (userbl.getEntity().getCustomer().getCurrentOrderId() == null) {
throw new SessionInternalError("No main subscription order for userId: " + userId);
}
// get currency from the user
Integer currencyId = userbl.getCurrencyId();
// get language from the caller
userbl.set(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
// pricing fields
List<Record> records = null;
PricingField[] fieldsArray = PricingField.getPricingFieldsValue(
pricing);
if (fieldsArray != null) {
Record record = new Record();
for (PricingField field : fieldsArray) {
record.addField(field, false); // don't care about isKey
}
records = new ArrayList<Record>(1);
records.add(record);
}
List<OrderLineDTO> diffLines = null;
OrderBL bl = new OrderBL();
if (lines != null) {
// get the current order
bl.set(OrderBL.getOrCreateCurrentOrder(userId, date, currencyId, true));
List<OrderLineDTO> oldLines = OrderLineBL.copy(bl.getDTO().getLines());
// add the line to the current order
for (OrderLineWS line : lines) {
bl.addItem(line.getItemId(), line.getQuantityAsDecimal(), languageId, userId, getCallerCompanyId(), currencyId, records);
}
// process lines to update prices and details from the source items
processLines(bl.getEntity(), languageId, getCallerCompanyId(), userId, currencyId, pricing);
diffLines = OrderLineBL.diffOrderLines(oldLines, bl.getDTO().getLines());
// generate NewQuantityEvents
bl.checkOrderLineQuantities(oldLines, bl.getDTO().getLines(), getCallerCompanyId(), bl.getDTO().getId(), true);
} else if (records != null) {
// Since there are no lines, run the mediation process
// rules to create them.
PluggableTaskManager<IMediationProcess> tm =
new PluggableTaskManager<IMediationProcess>(
getCallerCompanyId(),
Constants.PLUGGABLE_TASK_MEDIATION_PROCESS);
IMediationProcess processTask = tm.getNextClass();
MediationResult result = new MediationResult("WS", true);
result.setUserId(userId);
result.setEventDate(date);
ArrayList results = new ArrayList(1);
results.add(result);
processTask.process(records, results, "WS");
diffLines = result.getDiffLines();
if (result.getCurrencyId() != null) {
currencyId = result.getCurrencyId();
}
// the mediation process might not have anything for you...
if (result.getCurrentOrder() == null) {
LOG.debug("Call to updateOrder did not resolve to a current order lines = " +
Arrays.toString(lines) + " fields= " + Arrays.toString(fieldsArray));
return null;
}
bl.set(result.getCurrentOrder());
} else {
throw new SessionInternalError("Both the order lines and " +
"pricing fields were null. At least one of either " +
"must be provided.");
}
// save the event
// assign to record DONE and BILLABLE status
MediationRecordStatusDTO status = new MediationRecordStatusDAS().find(Constants.MEDIATION_RECORD_STATUS_DONE_AND_BILLABLE);
MediationRecordDTO record = new MediationRecordDTO(String.valueOf(date.getTime()),
new Date(),
null,
status);
record = new MediationRecordDAS().save(record);
IMediationSessionBean mediation = (IMediationSessionBean) Context.getBean(Context.Name.MEDIATION_SESSION);
mediation.saveEventRecordLines(new ArrayList<OrderLineDTO>(diffLines), record, date,eventDescription);
// return the updated order
return bl.getWS(languageId);
} catch (Exception e) {
LOG.error("WS - getCurrentOrder", e);
throw new SessionInternalError("Error updating current order");
}
}
public OrderWS[] getUserSubscriptions(Integer userId) throws SessionInternalError {
if (userId == null) throw new SessionInternalError("User Id cannot be null.");
List<OrderDTO> subscriptions= new OrderDAS().findByUserSubscriptions(userId);
if (null == subscriptions)
{
return new OrderWS[0];
}
OrderWS[] orderArr= new OrderWS[subscriptions.size()];
OrderBL bl = null;
for(OrderDTO dto: subscriptions) {
bl= new OrderBL(dto);
orderArr[subscriptions.indexOf(dto)]= bl.getWS(getCallerLanguageId());
}
return orderArr;
}
public boolean updateOrderPeriods(OrderPeriodWS[] orderPeriods) throws SessionInternalError {
//IOrderSessionBean orderSession = Context.getBean(Context.Name.ORDER_SESSION);
List<OrderPeriodDTO> periodDtos= new ArrayList<OrderPeriodDTO>(orderPeriods.length);
OrderPeriodDAS periodDas= new OrderPeriodDAS();
OrderPeriodDTO periodDto= null;
for (OrderPeriodWS periodWS: orderPeriods) {
if ( null != periodWS.getId()) {
periodDto= periodDas.find(periodWS.getId());
}
if ( null == periodDto ) {
periodDto= new OrderPeriodDTO();
periodDto.setCompany(new CompanyDAS().find(getCallerCompanyId()));
//periodDto.setVersionNum(new Integer(0));
}
periodDto.setValue(periodWS.getValue());
if (null != periodWS.getPeriodUnitId()) {
periodDto.setUnitId(periodWS.getPeriodUnitId().intValue());
}
periodDto= periodDas.save(periodDto);
if (periodWS.getDescriptions() != null && periodWS.getDescriptions().size() > 0 ) {
periodDto.setDescription(((InternationalDescriptionWS)periodWS.getDescriptions().get(0)).getContent(), ((InternationalDescriptionWS)periodWS.getDescriptions().get(0)).getLanguageId());
}
LOG.debug("Converted to DTO: " + periodDto);
periodDas.flush();
periodDas.clear();
//periodDtos.add(periodDto);
periodDto= null;
}
//orderSession.setPeriods(getCallerLanguageId(), periodDtos.toArray(new OrderPeriodDTO[periodDtos.size()]));
return true;
}
public boolean deleteOrderPeriod(Integer periodId) throws SessionInternalError {
IOrderSessionBean orderSession = Context.getBean(Context.Name.ORDER_SESSION);
return orderSession.deletePeriod(periodId);
}
/*
* PAYMENT
*/
public Integer createPayment(PaymentWS payment) {
return applyPayment(payment, null);
}
public void updatePayment(PaymentWS payment) {
PaymentDTOEx dto = new PaymentDTOEx(payment);
new PaymentBL(payment.getId()).update(getCallerId(), dto);
}
public void deletePayment(Integer paymentId) {
new PaymentBL(paymentId).delete();
}
/**
* Enters a payment and applies it to the given invoice. This method DOES NOT process
* the payment but only creates it as 'Entered'. The entered payment will later be
* processed by the billing process.
*
* Invoice ID is optional. If no invoice ID is given the payment will be applied to
* the payment user's account according to the configured entity preferences.
*
* @param payment payment to apply
* @param invoiceId invoice id
* @return created payment id
* @throws SessionInternalError
*/
public Integer applyPayment(PaymentWS payment, Integer invoiceId)
throws SessionInternalError {
validatePayment(payment);
payment.setIsRefund(0);
if (payment.getMethodId() == null) {
throw new SessionInternalError("Cannot apply a payment without a payment method.",
new String[] { "PaymentWS,paymentMethodId,validation.error.apply.without.method" });
}
IPaymentSessionBean session = (IPaymentSessionBean) Context.getBean(Context.Name.PAYMENT_SESSION);
return session.applyPayment(new PaymentDTOEx(payment), invoiceId);
}
/**
* Processes a payment and applies it to the given invoice. This method will actively
* processes the payment using the configured payment plug-in.
*
* Payment is optional when an invoice ID is provided. If no payment is given, the payment
* will be processed using the invoiced user's configured "automatic payment" instrument.
*
* Invoice ID is optional. If no invoice ID is given the payment will be applied to the
* payment user's account according to the configured entity preferences.
*
* @param payment payment to process
* @param invoiceId invoice id
* @return payment authorization from the payment processor
*/
public PaymentAuthorizationDTOEx processPayment(PaymentWS payment, Integer invoiceId) {
if (payment == null && invoiceId != null)
return payInvoice(invoiceId);
validatePayment(payment);
Integer entityId = getCallerCompanyId();
PaymentDTOEx dto = new PaymentDTOEx(payment);
// payment without Credit Card or ACH, fetch the users primary payment instrument for use
if (payment.getCreditCard() == null && payment.getAch() == null) {
LOG.debug("processPayment() called without payment method, fetching users automatic payment instrument.");
PaymentDTO instrument;
try {
instrument = PaymentBL.findPaymentInstrument(entityId, payment.getUserId());
} catch (PluggableTaskException e) {
throw new SessionInternalError("Exception occurred fetching payment info plug-in.",
new String[] { "PaymentWS,baseUserId,validation.error.no.payment.instrument" });
} catch (TaskException e) {
throw new SessionInternalError("Exception occurred with plug-in when fetching payment instrument.",
new String[] { "PaymentWS,baseUserId,validation.error.no.payment.instrument" });
}
if (instrument == null || (instrument.getCreditCard() == null && instrument.getAch() == null)) {
throw new SessionInternalError("User " + payment.getUserId() + "does not have a default payment instrument.",
new String[] { "PaymentWS,baseUserId,validation.error.no.payment.instrument" });
}
dto.setCreditCard(instrument.getCreditCard());
dto.setAch(instrument.getAch());
}
// populate payment method based on the payment instrument
if (dto.getCreditCard() != null) {
dto.setPaymentMethod(new PaymentMethodDTO(dto.getCreditCard().getCcType()));
} else if (dto.getAch() != null) {
dto.setPaymentMethod(new PaymentMethodDTO(Constants.PAYMENT_METHOD_ACH));
}
// process payment
IPaymentSessionBean session = (IPaymentSessionBean) Context.getBean(Context.Name.PAYMENT_SESSION);
Integer result = session.processAndUpdateInvoice(dto, null, entityId);
LOG.debug("paymentBean.processAndUpdateInvoice() Id=" + result);
PaymentAuthorizationDTOEx auth = null;
if (dto != null && dto.getAuthorization() != null) {
LOG.debug("PaymentAuthorizationDTO Id =" + dto.getAuthorization().getId());
auth = new PaymentAuthorizationDTOEx(dto.getAuthorization().getOldDTO());
LOG.debug("PaymentAuthorizationDTOEx Id =" + auth.getId());
auth.setResult(result.equals(Constants.RESULT_OK));
} else {
auth = new PaymentAuthorizationDTOEx();
auth.setResult(result.equals(Constants.RESULT_FAIL));
}
return auth;
}
public PaymentWS getPayment(Integer paymentId)
throws SessionInternalError {
// get the info from the caller
UserBL userbl = new UserBL(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
PaymentBL bl = new PaymentBL(paymentId);
return PaymentBL.getWS(bl.getDTOEx(languageId));
}
public PaymentWS getLatestPayment(Integer userId) throws SessionInternalError {
PaymentWS retValue = null;
// get the info from the caller
UserBL userbl = new UserBL(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
PaymentBL bl = new PaymentBL();
Integer paymentId = bl.getLatest(userId);
if (paymentId != null) {
bl.set(paymentId);
retValue = PaymentBL.getWS(bl.getDTOEx(languageId));
}
return retValue;
}
public Integer[] getLastPayments(Integer userId, Integer number) throws SessionInternalError {
if (userId == null || number == null) {
return null;
}
UserBL userbl = new UserBL(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
PaymentBL payment = new PaymentBL();
return payment.getManyWS(userId, number, languageId);
}
public PaymentWS getUserPaymentInstrument(Integer userId) throws SessionInternalError {
PaymentDTO instrument;
try {
instrument = PaymentBL.findPaymentInstrument(getCallerCompanyId(), userId);
} catch (PluggableTaskException e) {
throw new SessionInternalError("Exception occurred fetching payment info plug-in.", e);
} catch (TaskException e) {
throw new SessionInternalError("Exception occurred with plug-in when fetching payment instrument.", e);
}
return instrument != null ? PaymentBL.getWS(new PaymentDTOEx(instrument)) : null;
}
public BigDecimal getTotalRevenueByUser (Integer userId) throws SessionInternalError {
return new PaymentDAS().findTotalRevenueByUser(userId);
}
/*
* ITEM
*/
public Integer createItem(ItemDTOEx item) throws SessionInternalError {
ItemBL itemBL = new ItemBL();
ItemDTO dto = itemBL.getDTO(item);
// get the info from the caller
UserBL bl = new UserBL(getCallerId());
Integer languageId = bl.getEntity().getLanguageIdField();
Integer entityId = bl.getEntityId(bl.getEntity().getUserId());
dto.setEntity(new CompanyDTO(entityId));
// call the creation
return itemBL.create(dto, languageId);
}
/**
* Retrieves an array of items for the caller's entity.
* @return an array of items from the caller's entity
*/
public ItemDTOEx[] getAllItems() throws SessionInternalError {
Integer entityId = getCallerCompanyId();
ItemBL itemBL = new ItemBL();
return itemBL.getAllItems(entityId);
}
/**
* Implementation of the User Transitions List webservice. This accepts a
* start and end date as arguments, and produces an array of data containing
* the user transitions logged in the requested time range.
* @param from Date indicating the lower limit for the extraction of transition
* logs. It can be <code>null</code>, in such a case, the extraction will start
* where the last extraction left off. If no extractions have been done so far and
* this parameter is null, the function will extract from the oldest transition
* logged.
* @param to Date indicatin the upper limit for the extraction of transition logs.
* It can be <code>null</code>, in which case the extraction will have no upper
* limit.
* @return UserTransitionResponseWS[] an array of objects containing the result
* of the extraction, or <code>null</code> if there is no data thas satisfies
* the extraction parameters.
*/
public UserTransitionResponseWS[] getUserTransitions(Date from, Date to)
throws SessionInternalError {
UserTransitionResponseWS[] result = null;
Integer last = null;
// Obtain the current entity and language Ids
UserBL user = new UserBL();
Integer callerId = getCallerId();
Integer entityId = getCallerCompanyId();
EventLogger evLog = EventLogger.getInstance();
if (from == null) {
last = evLog.getLastTransitionEvent(entityId);
}
if (last != null) {
result = user.getUserTransitionsById(entityId, last, to);
} else {
result = user.getUserTransitionsByDate(entityId, from, to);
}
if (result == null) {
LOG.info("Data retrieved but resultset is null");
} else {
LOG.info("Data retrieved. Result size = " + result.length);
}
// Log the last value returned if there was any. This happens always,
// unless the returned array is empty.
if (result != null && result.length > 0) {
LOG.info("Registering transition list event");
evLog.audit(callerId, null, Constants.TABLE_EVENT_LOG, callerId, EventLogger.MODULE_WEBSERVICES,
EventLogger.USER_TRANSITIONS_LIST, result[result.length - 1].getId(),
result[0].getId().toString(), null);
}
return result;
}
/**
* @return UserTransitionResponseWS[] an array of objects containing the result
* of the extraction, or <code>null</code> if there is no data thas satisfies
* the extraction parameters.
*/
public UserTransitionResponseWS[] getUserTransitionsAfterId(Integer id)
throws SessionInternalError {
UserTransitionResponseWS[] result = null;
// Obtain the current entity and language Ids
UserBL user = new UserBL();
Integer callerId = getCallerId();
Integer entityId = getCallerCompanyId();
EventLogger evLog = EventLogger.getInstance();
result = user.getUserTransitionsById(entityId, id, null);
if (result == null) {
LOG.debug("Data retrieved but resultset is null");
} else {
LOG.debug("Data retrieved. Result size = " + result.length);
}
// Log the last value returned if there was any. This happens always,
// unless the returned array is empty.
if (result != null && result.length > 0) {
LOG.debug("Registering transition list event");
evLog.audit(callerId, null, Constants.TABLE_EVENT_LOG, callerId, EventLogger.MODULE_WEBSERVICES,
EventLogger.USER_TRANSITIONS_LIST, result[result.length - 1].getId(),
result[0].getId().toString(), null);
}
return result;
}
public ItemDTOEx getItem(Integer itemId, Integer userId, String pricing) {
PricingField[] fields = PricingField.getPricingFieldsValue(pricing);
ItemBL helper = new ItemBL(itemId);
List<PricingField> f = new ArrayList<PricingField>();
if (fields != null) f.addAll(Arrays.asList(fields));
helper.setPricingFields(f);
UserBL caller = new UserBL(getCallerId());
Integer callerId = caller.getEntity().getUserId();
Integer entityId = caller.getEntityId(callerId);
Integer languageId = caller.getEntity().getLanguageIdField();
// use the currency of the given user if provided, otherwise
// default to the currency of the caller (admin user)
Integer currencyId = (userId != null
? new UserBL(userId).getCurrencyId()
: caller.getCurrencyId());
ItemDTOEx retValue = helper.getWS(helper.getDTO(languageId, userId, entityId, currencyId));
return retValue;
}
public Integer createItemCategory(ItemTypeWS itemType)
throws SessionInternalError {
UserBL bl = new UserBL(getCallerId());
Integer entityId = bl.getEntityId(bl.getEntity().getUserId());
ItemTypeDTO dto = new ItemTypeDTO();
dto.setDescription(itemType.getDescription());
dto.setOrderLineTypeId(itemType.getOrderLineTypeId());
dto.setEntity(new CompanyDTO(entityId));
ItemTypeBL itemTypeBL = new ItemTypeBL();
itemTypeBL.create(dto);
return itemTypeBL.getEntity().getId();
}
public void updateItemCategory(ItemTypeWS itemType) throws SessionInternalError {
UserBL bl = new UserBL(getCallerId());
Integer executorId = bl.getEntity().getUserId();
ItemTypeBL itemTypeBL = new ItemTypeBL(itemType.getId());
ItemTypeDTO dto = new ItemTypeDTO();
dto.setDescription(itemType.getDescription());
dto.setOrderLineTypeId(itemType.getOrderLineTypeId());
itemTypeBL.update(executorId, dto);
}
private Integer zero2null(Integer var) {
if (var != null && var.intValue() == 0) {
return null;
} else {
return var;
}
}
private Date zero2null(Date var) {
if (var != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(var);
if (cal.get(Calendar.YEAR) == 1) {
return null;
}
}
return var;
}
private void validateUser(UserWS newUser)
throws SessionInternalError {
// do the validation
if (newUser == null) {
throw new SessionInternalError("Null parameter");
}
// C# sends a 0 when it is null ...
newUser.setCurrencyId(zero2null(newUser.getCurrencyId()));
newUser.setPartnerId(zero2null(newUser.getPartnerId()));
newUser.setParentId(zero2null(newUser.getParentId()));
newUser.setMainRoleId(zero2null(newUser.getMainRoleId()));
newUser.setLanguageId(zero2null(newUser.getLanguageId()));
newUser.setStatusId(zero2null(newUser.getStatusId()));
// clean up the cc number from spaces and '-'
if (newUser.getCreditCard() != null &&
newUser.getCreditCard().getNumber() != null) {
newUser.getCreditCard().setNumber(CreditCardBL.cleanUpNumber(
newUser.getCreditCard().getNumber()));
}
// todo: additional hibernate validations
// additional validation
if (newUser.getMainRoleId().equals(Constants.TYPE_CUSTOMER) ||
newUser.getMainRoleId().equals(Constants.TYPE_PARTNER)) {
} else {
throw new SessionInternalError("Valid user roles are customer (5) " +
"and partner (4)");
}
if (newUser.getCurrencyId() != null &&
newUser.getCurrencyId().intValue() <= 0) {
throw new SessionInternalError("Invalid currency code");
}
if (newUser.getStatusId().intValue() <= 0) {
throw new SessionInternalError("Invalid status code");
}
}
private void validateOrder(OrderWS order) throws SessionInternalError {
if (order == null) {
throw new SessionInternalError("Null parameter");
}
order.setUserId(zero2null(order.getUserId()));
order.setPeriod(zero2null(order.getPeriod()));
order.setBillingTypeId(zero2null(order.getBillingTypeId()));
order.setStatusId(zero2null(order.getStatusId()));
order.setCurrencyId(zero2null(order.getCurrencyId()));
order.setNotificationStep(zero2null(order.getNotificationStep()));
order.setDueDateUnitId(zero2null(order.getDueDateUnitId()));
order.setDueDateValue(zero2null(order.getDueDateValue()));
order.setDfFm(zero2null(order.getDfFm()));
order.setAnticipatePeriods(zero2null(order.getAnticipatePeriods()));
order.setActiveSince(zero2null(order.getActiveSince()));
order.setActiveUntil(zero2null(order.getActiveUntil()));
order.setNextBillableDay(zero2null(order.getNextBillableDay()));
order.setLastNotified(null);
// CXF seems to pass empty array as null
if (order.getOrderLines() == null) {
order.setOrderLines(new OrderLineWS[0]);
}
// todo: additional hibernate validations
// the lines
for (int f = 0; f < order.getOrderLines().length; f++) {
OrderLineWS line = order.getOrderLines()[f];
if (line.getUseItem() == null) {
line.setUseItem(false);
}
line.setItemId(zero2null(line.getItemId()));
String error = "";
// if use the item, I need the item id
if (line.getUseItem()) {
if (line.getItemId() == null || line.getItemId().intValue() == 0) {
error += "OrderLineWS: if useItem == true the itemId is required - ";
}
if (line.getQuantityAsDecimal() == null || BigDecimal.ZERO.compareTo(line.getQuantityAsDecimal()) == 0) {
error += "OrderLineWS: if useItem == true the quantity is required - ";
}
} else {
// I need the amount and description
if (line.getAmount() == null) {
error += "OrderLineWS: if useItem == false the item amount " +
"is required - ";
}
if (line.getDescription() == null ||
line.getDescription().length() == 0) {
error += "OrderLineWS: if useItem == false the description " +
"is required - ";
}
}
if (error.length() > 0) {
throw new SessionInternalError(error);
}
}
}
private void validatePayment(PaymentWS payment)
throws SessionInternalError {
if (payment == null) {
throw new SessionInternalError("Null parameter");
}
payment.setBaseUserId(payment.getBaseUserId());
payment.setMethodId(payment.getMethodId());
payment.setCurrencyId(payment.getCurrencyId());
payment.setPaymentId(payment.getPaymentId());
// todo: additional hibernate validations
}
private InvoiceDTO doCreateInvoice(Integer orderId) {
try {
BillingProcessBL process = new BillingProcessBL();
InvoiceDTO invoice = process.generateInvoice(orderId, null);
return invoice;
} catch (Exception e) {
LOG.error("WS - create invoice:", e);
throw new SessionInternalError("Error while generating a new invoice");
}
}
private PaymentDTOEx doPayInvoice(InvoiceDTO invoice, CreditCardDTO creditCard)
throws SessionInternalError {
if (invoice.getBalance() == null || BigDecimal.ZERO.compareTo(invoice.getBalance()) >= 0) {
LOG.warn("Can not pay invoice: " + invoice.getId() + ", balance: " + invoice.getBalance());
return null;
}
IPaymentSessionBean payment = (IPaymentSessionBean) Context.getBean(
Context.Name.PAYMENT_SESSION);
PaymentDTOEx paymentDto = new PaymentDTOEx();
paymentDto.setIsRefund(0);
paymentDto.setAmount(invoice.getBalance());
paymentDto.setCreditCard(creditCard);
paymentDto.setCurrency(new CurrencyDAS().find(invoice.getCurrency().getId()));
paymentDto.setUserId(invoice.getBaseUser().getUserId());
paymentDto.setPaymentMethod(new PaymentMethodDAS().find(
com.sapienter.jbilling.common.Util.getPaymentMethod(
creditCard.getNumber())));
paymentDto.setPaymentDate(new Date());
// make the call
payment.processAndUpdateInvoice(paymentDto, invoice);
return paymentDto;
}
/**
* Conveniance method to find a credit card
*/
private CreditCardDTO getCreditCard(Integer userId) {
if (userId == null) {
return null;
}
CreditCardDTO result = null;
try {
UserBL user = new UserBL(userId);
Integer entityId = user.getEntityId(userId);
if (user.hasCreditCard()) {
// find it
PaymentDTOEx paymentDto = PaymentBL.findPaymentInstrument(
entityId, userId);
// it might have a credit card, but it might not be valid or
// just not found by the plug-in
if (paymentDto != null) {
result = paymentDto.getCreditCard();
}
}
} catch (Exception e) { // forced by checked exceptions :(
LOG.error("WS - finding a credit card", e);
throw new SessionInternalError("Error finding a credit card for user: " + userId);
}
return result;
}
private OrderWS doCreateOrder(OrderWS order, boolean create)
throws SessionInternalError {
validateOrder(order);
// get the info from the caller
UserBL bl = new UserBL(getCallerId());
Integer executorId = bl.getEntity().getUserId();
Integer entityId = bl.getEntityId(bl.getEntity().getUserId());
// we'll need the langauge later
bl.set(order.getUserId());
Integer languageId = bl.getEntity().getLanguageIdField();
// convert to a DTO
OrderBL orderBL = new OrderBL();
OrderDTO dto = orderBL.getDTO(order);
// process the lines and let the items provide the order line details
LOG.debug("Processing order lines");
processLines(dto, languageId, entityId, order.getUserId(), order.getCurrencyId(), order.getPricingFields());
LOG.info("before cycle start");
// set a default cycle starts if needed (obtained from the main
// subscription order, if it exists)
if (dto.getCycleStarts() == null && dto.getIsCurrent() == null) {
Integer mainOrderId = orderBL.getMainOrderId(dto.getUser().getId());
if (mainOrderId != null) {
// only set a default if preference use current order is set
PreferenceBL preferenceBL = new PreferenceBL();
try {
preferenceBL.set(entityId, Constants.PREFERENCE_USE_CURRENT_ORDER);
} catch (EmptyResultDataAccessException e) {
// default preference will be used
}
if (preferenceBL.getInt() != 0) {
OrderDAS das = new OrderDAS();
OrderDTO mainOrder = das.findNow(mainOrderId);
LOG.debug("Copying cycle starts from main order");
dto.setCycleStarts(mainOrder.getCycleStarts());
}
}
}
orderBL.set(dto);
orderBL.recalculate(entityId);
if (create) {
LOG.debug("creating order");
dto.setId(null);
dto.setVersionNum(null);
for (OrderLineDTO line : dto.getLines()) {
line.setId(0);
line.setVersionNum(null);
}
Integer id = orderBL.create(entityId, executorId, dto);
orderBL.set(id);
return orderBL.getWS(languageId);
}
return getWSFromOrder(orderBL, languageId);
}
private OrderWS getWSFromOrder(OrderBL bl, Integer languageId) {
OrderDTO order = bl.getDTO();
OrderWS retValue = new OrderWS(order.getId(), order.getBillingTypeId(),
order.getNotify(), order.getActiveSince(), order.getActiveUntil(),
order.getCreateDate(), order.getNextBillableDay(),
order.getCreatedBy(), order.getStatusId(), order.getDeleted(),
order.getCurrencyId(), order.getLastNotified(),
order.getNotificationStep(), order.getDueDateUnitId(),
order.getDueDateValue(), order.getAnticipatePeriods(),
order.getDfFm(), order.getIsCurrent(), order.getNotes(),
order.getNotesInInvoice(), order.getOwnInvoice(),
order.getOrderPeriod().getId(),
order.getBaseUserByUserId().getId(),
order.getVersionNum(), order.getCycleStarts());
retValue.setPeriodStr(order.getOrderPeriod().getDescription(languageId));
retValue.setBillingTypeStr(order.getOrderBillingType().getDescription(languageId));
retValue.setTotal(order.getTotal());
List<OrderLineWS> lines = new ArrayList<OrderLineWS>();
for (Iterator<OrderLineDTO> it = order.getLines().iterator(); it.hasNext();) {
OrderLineDTO line = (OrderLineDTO) it.next();
LOG.info("copying line: " + line);
if (line.getDeleted() == 0) {
OrderLineWS lineWS = new OrderLineWS(line.getId(), line.getItem().getId(), line.getDescription(),
line.getAmount(), line.getQuantity(), line.getPrice(),
line.getCreateDatetime(), line.getDeleted(), line.getOrderLineType().getId(),
line.getEditable(), (line.getPurchaseOrder() != null?line.getPurchaseOrder().getId():null),
null, line.getVersionNum(),line.getProvisioningStatusId(),line.getProvisioningRequestId());
lines.add(lineWS);
}
}
retValue.setOrderLines(new OrderLineWS[lines.size()]);
lines.toArray(retValue.getOrderLines());
return retValue;
}
private InvoiceDTO findInvoice(Integer invoiceId) {
final InvoiceDTO invoice;
invoice = new InvoiceBL(invoiceId).getEntity();
return invoice;
}
// TODO: This method is not secured or in a jUnit test
public InvoiceWS getLatestInvoiceByItemType(Integer userId, Integer itemTypeId)
throws SessionInternalError {
InvoiceWS retValue = null;
try {
if (userId == null) {
return null;
}
InvoiceBL bl = new InvoiceBL();
Integer invoiceId = bl.getLastByUserAndItemType(userId, itemTypeId);
if (invoiceId != null) {
retValue = bl.getWS(new InvoiceDAS().find(invoiceId));
}
return retValue;
} catch (Exception e) { // forced by SQLException
LOG.error("Exception in web service: getting latest invoice" +
" for user " + userId, e);
throw new SessionInternalError("Error getting latest invoice");
}
}
/**
* Return 'number' most recent invoices that contain a line item with an
* item of the given item type.
*/
// TODO: This method is not secured or in a jUnit test
public Integer[] getLastInvoicesByItemType(Integer userId, Integer itemTypeId, Integer number)
throws SessionInternalError {
if (userId == null || itemTypeId == null || number == null) {
return null;
}
InvoiceBL bl = new InvoiceBL();
return bl.getManyByItemTypeWS(userId, itemTypeId, number);
}
// TODO: This method is not secured or in a jUnit test
public OrderWS getLatestOrderByItemType(Integer userId, Integer itemTypeId)
throws SessionInternalError {
if (userId == null) {
throw new SessionInternalError("User id can not be null");
}
if (itemTypeId == null) {
throw new SessionInternalError("itemTypeId can not be null");
}
OrderWS retValue = null;
// get the info from the caller
UserBL userbl = new UserBL(getCallerId());
Integer languageId = userbl.getEntity().getLanguageIdField();
// now get the order
OrderBL bl = new OrderBL();
Integer orderId = bl.getLatestByItemType(userId, itemTypeId);
if (orderId != null) {
bl.set(orderId);
retValue = bl.getWS(languageId);
}
return retValue;
}
// TODO: This method is not secured or in a jUnit test
public Integer[] getLastOrdersByItemType(Integer userId, Integer itemTypeId, Integer number)
throws SessionInternalError {
if (userId == null || number == null) {
return null;
}
OrderBL order = new OrderBL();
return order.getListIdsByItemType(userId, itemTypeId, number);
}
public String isUserSubscribedTo(Integer userId, Integer itemId) {
OrderDAS das = new OrderDAS();
BigDecimal quantity = das.findIsUserSubscribedTo(userId, itemId);
return quantity != null ? quantity.toString() : null;
}
public Integer[] getUserItemsByCategory(Integer userId, Integer categoryId) {
Integer[] result = null;
OrderDAS das = new OrderDAS();
result = das.findUserItemsByCategory(userId, categoryId);
return result;
}
public ItemDTOEx[] getItemByCategory(Integer itemTypeId) {
return new ItemBL().getAllItemsByType(itemTypeId);
}
public ItemTypeWS[] getAllItemCategories() {
return new ItemTypeBL().getAllItemTypes();
}
public ValidatePurchaseWS validatePurchase(Integer userId, Integer itemId,
String fields) {
Integer[] itemIds = null;
if (itemId != null) {
itemIds = new Integer[] { itemId };
}
String[] fieldsArray = null;
if (fields != null) {
fieldsArray = new String[] { fields };
}
return doValidatePurchase(userId, itemIds, fieldsArray);
}
public ValidatePurchaseWS validateMultiPurchase(Integer userId,
Integer[] itemIds, String[] fields) {
return doValidatePurchase(userId, itemIds, fields);
}
private ValidatePurchaseWS doValidatePurchase(Integer userId, Integer[] itemIds, String[] fields) {
if (userId == null || (itemIds == null && fields == null)) {
return null;
}
List<List<PricingField>> fieldsList = null;
if (fields != null) {
fieldsList = new ArrayList<List<PricingField>>(fields.length);
for (int i = 0; i < fields.length; i++) {
fieldsList.add(new ArrayList(Arrays.asList(PricingField.getPricingFieldsValue(fields[i]))));
}
}
List<Integer> itemIdsList = null;
List<BigDecimal> prices = new ArrayList<BigDecimal>();
List<ItemDTO> items = new ArrayList<ItemDTO>();
if (itemIds != null) {
itemIdsList = new ArrayList(Arrays.asList(itemIds));
} else if (fields != null) {
itemIdsList = new LinkedList<Integer>();
for (List<PricingField> pricingFields : fieldsList) {
try {
// Since there is no item, run the mediation process rules
// to create line/s. This will run pricing and
// item management rules as well
// fields need to be in records
Record record = new Record();
for (PricingField field : pricingFields) {
record.addField(field, false); // don't care about isKey
}
List<Record> records = new ArrayList<Record>(1);
records.add(record);
PluggableTaskManager<IMediationProcess> tm
= new PluggableTaskManager<IMediationProcess>(getCallerCompanyId(),
Constants.PLUGGABLE_TASK_MEDIATION_PROCESS);
IMediationProcess processTask = tm.getNextClass();
MediationResult result = new MediationResult("WS", false);
result.setUserId(userId);
result.setEventDate(new Date());
ArrayList results = new ArrayList(1);
results.add(result);
processTask.process(records, results, "WS");
// from the lines, get the items and prices
for (OrderLineDTO line : result.getDiffLines()) {
items.add(new ItemBL(line.getItemId()).getEntity());
prices.add(line.getAmount());
}
} catch (Exception e) {
// log stacktrace
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.close();
LOG.error("Validate Purchase error: " + e.getMessage() + "\n" + sw.toString());
ValidatePurchaseWS result = new ValidatePurchaseWS();
result.setSuccess(false);
result.setAuthorized(false);
result.setQuantity(BigDecimal.ZERO);
result.setMessage(new String[] { "Error: " + e.getMessage() } );
return result;
}
}
} else {
return null;
}
// find the prices first
// this will do nothing if the mediation process was uses. In that case
// the itemIdsList will be empty
int itemNum = 0;
for (Integer itemId : itemIdsList) {
ItemBL item = new ItemBL(itemId);
if (fieldsList != null && !fieldsList.isEmpty()) {
int fieldsIndex = itemNum;
// just get first set of fields if only one set
// for many items
if (fieldsIndex > fieldsList.size()) {
fieldsIndex = 0;
}
item.setPricingFields(fieldsList.get(fieldsIndex));
}
// todo: validate purchase should include the quantity purchased for validations
prices.add(item.getPrice(userId, BigDecimal.ONE, getCallerCompanyId()));
items.add(item.getEntity());
itemNum++;
}
ValidatePurchaseWS ret = new UserBL(userId).validatePurchase(items, prices, fieldsList);
return ret;
}
/**
* Updates a users stored credit card.
*
* @param userId user to update
* @param creditCard credit card details
* @throws SessionInternalError
*/
public void updateCreditCard(Integer userId, com.sapienter.jbilling.server.entity.CreditCardDTO creditCard)
throws SessionInternalError {
if (creditCard == null)
return;
if (creditCard.getName() == null || creditCard.getExpiry() == null)
throw new SessionInternalError("Missing credit card name or expiry date");
IUserSessionBean userSession = Context.getBean(Context.Name.USER_SESSION);
userSession.updateCreditCard(getCallerId(), userId, new CreditCardDTO(creditCard));
}
/**
* Deletes a users stored credit card. Payments that were made using the deleted credit
* card will not be affected.
*
* @param userId user to delete the credit card from
*/
public void deleteCreditCard(Integer userId) {
IUserSessionBean userSession = Context.getBean(Context.Name.USER_SESSION);
userSession.deleteCreditCard(getCallerId(), userId);
}
/**
* Updates a users stored ACH details.
*
* @param userId user to update
* @param ach ach details
* @throws SessionInternalError
*/
public void updateAch(Integer userId, com.sapienter.jbilling.server.entity.AchDTO ach)
throws SessionInternalError {
if (ach == null)
return;
if (ach.getAbaRouting() == null || ach.getBankAccount() == null)
throw new SessionInternalError("Missing ACH routing number of bank account number.");
IUserSessionBean userSession = Context.getBean(Context.Name.USER_SESSION);
userSession.updateACH(userId, getCallerId(), new AchDTO(ach));
}
/**
* Deletes a users stored ACH details. Payments that were made using the deleted ACH
* details will not be affected.
*
* @param userId user to delete the ACH details from.
*/
public void deleteAch(Integer userId) {
IUserSessionBean userSession = Context.getBean(Context.Name.USER_SESSION);
userSession.removeACH(userId, getCallerId());
}
public Integer getAuthPaymentType(Integer userId)
throws SessionInternalError {
IUserSessionBean sess = (IUserSessionBean) Context.getBean(
Context.Name.USER_SESSION);
return sess.getAuthPaymentType(userId);
}
public void setAuthPaymentType(Integer userId, Integer autoPaymentType, boolean use)
throws SessionInternalError {
IUserSessionBean sess = (IUserSessionBean) Context.getBean(
Context.Name.USER_SESSION);
sess.setAuthPaymentType(userId, autoPaymentType, use);
}
public AgeingWS[] getAgeingConfiguration(Integer languageId) throws SessionInternalError {
try {
IBillingProcessSessionBean processSession =
(IBillingProcessSessionBean) Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
AgeingDTOEx[] dtoArr= processSession.getAgeingSteps(getCallerCompanyId(), getCallerLanguageId(), languageId);
AgeingWS[] wsArr= new AgeingWS[dtoArr.length];
AgeingBL bl= new AgeingBL();
for (int i = 0; i < wsArr.length; i++) {
wsArr[i]= bl.getWS(dtoArr[i]);
}
return wsArr;
} catch (Exception e) {
throw new SessionInternalError(e);
}
}
public void saveAgeingConfiguration(AgeingWS[] steps, Integer gracePeriod, Integer languageId) throws SessionInternalError {
AgeingBL bl= new AgeingBL();
AgeingDTOEx[] dtoList= new AgeingDTOEx[steps.length];
for (int i = 0; i < steps.length; i++) {
dtoList[i]= bl.getDTOEx(steps[i]);
}
IBillingProcessSessionBean processSession =
(IBillingProcessSessionBean) Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
processSession.setAgeingSteps (getCallerCompanyId(), languageId, bl.validate(dtoList));
// update the grace period in another call
IUserSessionBean userSession = (IUserSessionBean) Context.getBean(Context.Name.USER_SESSION);
userSession.setEntityParameter(getCallerCompanyId(),
Constants.PREFERENCE_GRACE_PERIOD,
(gracePeriod != null ? gracePeriod.toString() : null));
}
/*
Billing process
*/
public boolean isBillingRunning() {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
return processBean.isBillingRunning();
}
public void triggerBillingAsync(final Date runDate) {
Thread t =new Thread(new Runnable(){
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
public void run()
{
processBean.trigger(runDate);
}
});
t.start();
}
public boolean triggerBilling(Date runDate) {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
return processBean.trigger(runDate);
}
public void triggerAgeing(Date runDate) {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
processBean.reviewUsersStatus(getCallerCompanyId(), runDate);
}
public BillingProcessConfigurationWS getBillingProcessConfiguration() throws SessionInternalError {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
BillingProcessConfigurationDTO configuration = processBean.getConfigurationDto(getCallerCompanyId());
return ConfigurationBL.getWS(configuration);
}
public Integer createUpdateBillingProcessConfiguration(BillingProcessConfigurationWS ws)
throws SessionInternalError {
//validation
if (!ConfigurationBL.validate(ws)) {
throw new SessionInternalError("Error: Invalid Next Run Date.");
}
BillingProcessConfigurationDTO dto = ConfigurationBL.getDTO(ws);
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
return processBean.createUpdateConfiguration(getCallerId(), dto);
}
public BillingProcessWS getBillingProcess(Integer processId) {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
BillingProcessDTOEx dto = processBean.getDto(processId, getCallerLanguageId());
return BillingProcessBL.getWS(dto);
}
public Integer getLastBillingProcess() throws SessionInternalError {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
return processBean.getLast(getCallerCompanyId());
}
public List<OrderProcessWS> getOrderProcesses(Integer orderId) {
OrderDTO order = new OrderBL(orderId).getDTO();
if (order == null)
return Collections.emptyList();
List<OrderProcessWS> ws = new ArrayList<OrderProcessWS>(order.getOrderProcesses().size());
for (OrderProcessDTO process : order.getOrderProcesses())
ws.add(new OrderProcessWS(process));
return ws;
}
public List<OrderProcessWS> getOrderProcessesByInvoice(Integer invoiceId) {
InvoiceDTO invoice = new InvoiceBL(invoiceId).getDTO();
if (invoice == null)
return Collections.emptyList();
List<OrderProcessWS> ws = new ArrayList<OrderProcessWS>(invoice.getOrderProcesses().size());
for (OrderProcessDTO process : invoice.getOrderProcesses())
ws.add(new OrderProcessWS(process));
return ws;
}
public BillingProcessWS getReviewBillingProcess() {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
BillingProcessDTOEx dto = processBean.getReviewDto(getCallerCompanyId(), getCallerLanguageId());
return BillingProcessBL.getWS(dto);
}
public BillingProcessConfigurationWS setReviewApproval(Boolean flag) throws SessionInternalError {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
BillingProcessConfigurationDTO dto = processBean.setReviewApproval(getCallerId(), getCallerCompanyId(), flag);
return ConfigurationBL.getWS(dto);
}
public List<Integer> getBillingProcessGeneratedInvoices(Integer processId) {
IBillingProcessSessionBean processBean = Context.getBean(Context.Name.BILLING_PROCESS_SESSION);
// todo: IBillingProcessSessionBean#getGeneratedInvoices() should have a proper generic return type
@SuppressWarnings("unchecked")
Collection<InvoiceDTO> invoices = processBean.getGeneratedInvoices(processId);
List<Integer> ids = new ArrayList<Integer>(invoices.size());
for (InvoiceDTO invoice : invoices)
ids.add(invoice.getId());
return ids;
}
/*
Mediation process
*/
public void triggerMediation() {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
mediationBean.trigger(getCallerCompanyId());
}
public boolean isMediationProcessing() throws SessionInternalError {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
return mediationBean.isProcessing(getCallerCompanyId());
}
public List<MediationProcessWS> getAllMediationProcesses() {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
List<MediationProcess> processes = mediationBean.getAll(getCallerCompanyId());
// convert to web-service mediation process
List<MediationProcessWS> ws = new ArrayList<MediationProcessWS>(processes.size());
for (MediationProcess process : processes)
ws.add(new MediationProcessWS(process));
return ws;
}
public List<MediationRecordLineWS> getMediationEventsForOrder(Integer orderId) {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
List<MediationRecordLineDTO> events = mediationBean.getEventsForOrder(orderId);
return MediationRecordBL.getWS(events);
}
public List<MediationRecordLineWS> getMediationEventsForInvoice(Integer invoiceId) {
List<MediationRecordLineDTO> events = new MediationRecordLineDAS().findByInvoice(invoiceId);
return MediationRecordBL.getWS(events);
}
public List<MediationRecordWS> getMediationRecordsByMediationProcess(Integer mediationProcessId) {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
List<MediationRecordDTO> records = mediationBean.getMediationRecordsByMediationProcess(mediationProcessId);
return MediationRecordBL.getWS(records);
}
public List<RecordCountWS> getNumberOfMediationRecordsByStatuses() {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
Map<MediationRecordStatusDTO, Long> records = mediationBean.getNumberOfRecordsByStatuses(getCallerCompanyId());
// convert to a simple object for web-services
List<RecordCountWS> counts = new ArrayList<RecordCountWS>(records.size());
for (Map.Entry<MediationRecordStatusDTO, Long> record : records.entrySet())
counts.add(new RecordCountWS(record.getKey().getId(), record.getValue()));
return counts;
}
public List<MediationConfigurationWS> getAllMediationConfigurations() {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
List<MediationConfiguration> configurations = mediationBean.getAllConfigurations(getCallerCompanyId());
return MediationConfigurationBL.getWS(configurations);
}
public void createMediationConfiguration(MediationConfigurationWS cfg) {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
MediationConfiguration dto = MediationConfigurationBL.getDTO(cfg);
mediationBean.createConfiguration(dto);
}
public List<Integer> updateAllMediationConfigurations(List<MediationConfigurationWS> configurations)
throws SessionInternalError {
// update all configurations
List<MediationConfiguration> dtos = MediationConfigurationBL.getDTO(configurations);
List<MediationConfiguration> updated;
try {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
updated = mediationBean.updateAllConfiguration(getCallerId(), dtos);
} catch (InvalidArgumentException e) {
throw new SessionInternalError(e);
}
// return list of updated ids
List<Integer> ids = new ArrayList<Integer>(updated.size());
for (MediationConfiguration cfg : updated)
ids.add(cfg.getId());
return ids;
}
public void deleteMediationConfiguration(Integer cfgId) {
IMediationSessionBean mediationBean = Context.getBean(Context.Name.MEDIATION_SESSION);
mediationBean.delete(getCallerId(), cfgId);
}
/*
Provisioning
*/
public void triggerProvisioning() {
IProvisioningProcessSessionBean provisioningBean = Context.getBean(Context.Name.PROVISIONING_PROCESS_SESSION);
provisioningBean.trigger();
}
public void updateOrderAndLineProvisioningStatus(Integer inOrderId, Integer inLineId, String result)
throws SessionInternalError {
IProvisioningProcessSessionBean provisioningBean = Context.getBean(Context.Name.PROVISIONING_PROCESS_SESSION);
provisioningBean.updateProvisioningStatus(inOrderId, inLineId, result);
}
public void updateLineProvisioningStatus(Integer orderLineId, Integer provisioningStatus) throws SessionInternalError {
IProvisioningProcessSessionBean provisioningBean = Context.getBean(Context.Name.PROVISIONING_PROCESS_SESSION);
provisioningBean.updateProvisioningStatus(orderLineId, provisioningStatus);
}
/*
Utilities
*/
public void generateRules(String rulesData) throws SessionInternalError {
try {
PluggableTaskManager<IRulesGenerator> tm =
new PluggableTaskManager<IRulesGenerator>(
getCallerCompanyId(),
Constants.PLUGGABLE_TASK_RULES_GENERATOR);
IRulesGenerator rulesGenerator = tm.getNextClass();
rulesGenerator.unmarshal(rulesData);
rulesGenerator.process();
} catch (Exception e) {
throw new SessionInternalError(e);
}
}
/*
Preferences
*/
public void updatePreferences(PreferenceWS[] prefList) {
PreferenceBL bl = new PreferenceBL();
for (PreferenceWS pref: prefList) {
bl.createUpdateForEntity(getCallerCompanyId(), pref.getPreferenceType().getId(), pref.getValue());
}
}
public void updatePreference(PreferenceWS preference) {
new PreferenceBL().createUpdateForEntity(getCallerCompanyId(),
preference.getPreferenceType().getId(),
preference.getValue());
}
public PreferenceWS getPreference(Integer preferenceTypeId) {
PreferenceDTO preference = null;
try {
preference = new PreferenceBL(getCallerCompanyId(), preferenceTypeId).getEntity();
} catch (DataAccessException e) {
/* ignore */
}
if (preference != null) {
// return preference if set
return new PreferenceWS(preference);
} else {
// preference is not set, return empty
PreferenceTypeDTO preferenceType = new PreferenceTypeDAS().find(preferenceTypeId);
return preferenceType != null ? new PreferenceWS(preferenceType) : null;
}
}
/*
Currencies
*/
public CurrencyWS[] getCurrencies() {
CurrencyBL currencyBl = new CurrencyBL();
CurrencyDTO[] currencies;
try {
currencies = currencyBl.getCurrencies(getCallerCompanyId(), getCallerLanguageId());
} catch (SQLException e) {
throw new SessionInternalError("Exception fetching currencies for entity " + getCallerCompanyId(), e);
} catch (NamingException e) {
throw new SessionInternalError("Exception fetching currencies for entity " + getCallerCompanyId(), e);
}
// Id of the default currency for this entity
Integer entityDefault = currencyBl.getEntityCurrency(getCallerCompanyId());
// convert to WS
List<CurrencyWS> ws = new ArrayList<CurrencyWS>(currencies.length);
for (CurrencyDTO currency : currencies) {
ws.add(new CurrencyWS(currency, (currency.getId() == entityDefault)));
}
return ws.toArray(new CurrencyWS[ws.size()]);
}
public void updateCurrencies(CurrencyWS[] currencies) {
for (CurrencyWS currency : currencies) {
updateCurrency(currency);
}
}
public void updateCurrency(CurrencyWS ws) {
CurrencyDTO currency = new CurrencyDTO(ws);
// update currency
CurrencyBL currencyBl = new CurrencyBL(currency.getId());
currencyBl.update(currency, getCallerCompanyId());
// set as entity currency if flagged as default
if (ws.isDefaultCurrency()) {
currencyBl.setEntityCurrency(getCallerCompanyId(), currency.getId());
}
// update the description if its changed
if ((ws.getDescription() != null && !ws.getDescription().equals(currency.getDescription()))) {
currency.setDescription(ws.getDescription(), getCallerLanguageId());
}
}
public Integer createCurrency(CurrencyWS ws) {
CurrencyDTO currency = new CurrencyDTO(ws);
// save new currency
CurrencyBL currencyBl = new CurrencyBL(currency.getId());
currencyBl.create(currency, getCallerCompanyId());
currency = currencyBl.getEntity();
// set as entity currency if flagged as default
if (ws.isDefaultCurrency()) {
currencyBl.setEntityCurrency(getCallerCompanyId(), currency.getId());
}
// set description
if (ws.getDescription() != null) {
currency.setDescription(ws.getDescription(), getCallerLanguageId());
}
return currency.getId();
}
public CompanyWS getCompany() {
CompanyDTO company= new CompanyDAS().find(getCallerCompanyId());
LOG.debug(company);
return new CompanyWS(company);
}
public void updateCompany(CompanyWS companyWS) {
new EntityBL().updateEntityAndContact(companyWS, getCallerCompanyId(), getCallerId());
}
/*
Notifications
*/
public void createUpdateNofications(Integer messageId, MessageDTO dto) {
if (null == messageId) {
new NotificationBL().createUpdate(getCallerCompanyId(), dto);
} else {
new NotificationBL(messageId).createUpdate(getCallerCompanyId(), dto);
}
}
/*Secured via WSSecurityMethodMapper entry.*/
public void saveCustomerNotes(Integer userId, String notes) {
CustomerDTO cust= UserBL.getUserEntity(userId).getCustomer();
if ( null != cust ) {
cust.setNotes(notes);
} else {
throw new SessionInternalError("Not a customer");
}
}
/*
* Plug-ins
*/
public PluggableTaskWS getPluginWS(Integer pluginId) {
PluggableTaskDTO dto = new PluggableTaskBL(pluginId).getDTO();
return new PluggableTaskWS(dto);
}
public Integer createPlugin(PluggableTaskWS plugin) {
return new PluggableTaskBL().create(getCallerId(), new PluggableTaskDTO(getCallerCompanyId(), plugin));
}
public void updatePlugin(PluggableTaskWS plugin) {
new PluggableTaskBL().update(getCallerId(), new PluggableTaskDTO(getCallerCompanyId(), plugin));
}
public void deletePlugin(Integer id) {
new PluggableTaskBL(id).delete(getCallerId());
}
}