/*
* Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wso2.carbon.billing.core;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.billing.core.beans.OutstandingBalanceInfoBean;
import org.wso2.carbon.billing.core.conf.BillingTaskConfiguration;
import org.wso2.carbon.billing.core.dataobjects.*;
import org.wso2.carbon.billing.core.internal.Util;
import org.wso2.carbon.billing.core.jdbc.DataAccessObject;
import org.wso2.carbon.billing.core.scheduler.BillingScheduler;
import org.wso2.carbon.billing.core.scheduler.SchedulerContext;
import org.wso2.carbon.billing.core.utilities.CustomerUtils;
import org.wso2.carbon.email.sender.api.EmailSender;
import org.wso2.carbon.email.sender.api.EmailSenderConfiguration;
import org.wso2.carbon.user.api.Tenant;
import org.wso2.carbon.user.api.TenantManager;
import org.wso2.carbon.utils.CarbonUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Billing engine work on billing per a seller
*/
public class BillingEngine {
private static Log log = LogFactory.getLog(BillingEngine.class);
//private static long lastBillGenerationTime = 0;
private BillingTaskConfiguration billingTaskConfig;
BillingScheduler billingScheduler;
DataAccessObject dataAccessObject;
public BillingEngine(BillingTaskConfiguration billingTaskConfig,
DataAccessObject dataAccessObject) {
this.billingTaskConfig = billingTaskConfig;
billingScheduler = new BillingScheduler(this, billingTaskConfig);
this.dataAccessObject = dataAccessObject;
}
public void scheduleBilling() throws BillingException {
// the logic to schedule the billing
SchedulerContext schedulerContext = billingScheduler.createScheduleContext();
billingScheduler.scheduleNextCycle(schedulerContext);
}
public void generateBill() throws BillingException {
BillingEngineContext billingEngineContext = new BillingEngineContext();
generateBill(billingEngineContext);
}
public void generateBill(SchedulerContext schedulerContext) throws BillingException {
BillingEngineContext billingEngineContext = new BillingEngineContext();
billingEngineContext.setSchedulerContext(schedulerContext);
generateBill(billingEngineContext);
}
public void generateBill(BillingEngineContext billingEngineContext) throws BillingException {
/*long timeDifference = new Date().getTime() - lastBillGenerationTime;
if(timeDifference < 100000L){
log.warn("Trying to generate the bill too frequently. Time difference between this one and lastone is " + timeDifference + "milliseconds");
return;
}else{
lastBillGenerationTime = new Date().getTime();
}*/
boolean successful = false;
try {
beginTransaction();
if (billingEngineContext.getSchedulerContext() == null) {
SchedulerContext schedulerContext = billingScheduler.createScheduleContext();
billingEngineContext.setSchedulerContext(schedulerContext);
}
billingEngineContext.setTaskConfiguration(billingTaskConfig);
// now iterator through all the handlers
List<BillingHandler> handlers = billingTaskConfig.getBillingHandlers();
log.debug("Found " + handlers.size() + " handlers");
for (BillingHandler handler : handlers) {
log.debug("Executing: " + handler.getClass());
handler.execute(billingEngineContext);
}
successful = true;
}catch (Exception e){
String msg = "Error occurred while generating the bill:" + e.getMessage();
log.error(msg);
throw new BillingException(msg, e);
}finally {
if (successful) {
commitTransaction();
} else {
rollbackTransaction();
}
}
}
public void beginTransaction() throws BillingException {
dataAccessObject.beginTransaction();
}
public void commitTransaction() throws BillingException {
dataAccessObject.commitTransaction();
}
public void rollbackTransaction() throws BillingException {
dataAccessObject.rollbackTransaction();
}
public List<Item> getItemsWithName(String itemName) throws BillingException {
boolean successful = false;
List<Item> items;
try {
dataAccessObject.beginTransaction();
items = dataAccessObject.getItemsWithName(itemName);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return items;
}
public void deleteItem(int itemId) throws BillingException {
boolean successful = false;
try {
dataAccessObject.beginTransaction();
//dataAccessObject.deleteItem(itemId);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
}
public int addItem(Item item) throws BillingException {
boolean successful = false;
int itemId = 0;
try {
dataAccessObject.beginTransaction();
itemId = dataAccessObject.addItem(item);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return itemId;
}
public Item getItem(int itemId) throws BillingException {
boolean successful = false;
Item item;
try {
dataAccessObject.beginTransaction();
item = dataAccessObject.getItem(itemId);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return item;
}
public List<Customer> getCustomersWithName(String customerName) throws BillingException {
TenantManager tenantManager = Util.getRealmService().getTenantManager();
List<Customer> customers = new ArrayList<Customer>();
try{
int tenantId = tenantManager.getTenantId(customerName);
Tenant tenant = tenantManager.getTenant(tenantId);
if(tenant!=null){
Customer customer = new Customer();
customer.setId(tenant.getId());
customer.setName(tenant.getDomain());
customer.setStartedDate(tenant.getCreatedDate());
customer.setEmail(tenant.getEmail());
//customer.setAddress();
customers.add(customer);
}
}catch(Exception e){
String msg = "Failed to get customers for customers: " + customerName + ".";
log.error(msg, e);
throw new BillingException(msg, e);
}
return customers;
}
public void deleteCustomer(int customerId) throws BillingException {
boolean successful = false;
try {
dataAccessObject.beginTransaction();
//dataAccessObject.deleteCustomer(customerId);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
}
public int addCustomer(Customer customer) throws BillingException {
boolean successful = false;
int customerId = 0;
try {
dataAccessObject.beginTransaction();
//customerId = dataAccessObject.addCustomer(customer);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return customerId;
}
public int addSubscription(Subscription subscription) throws BillingException {
boolean successful = false;
int subscriptionId = 0;
try {
dataAccessObject.beginTransaction();
subscriptionId =
dataAccessObject.addSubscription(subscription,
billingTaskConfig.getSubscriptionFilter());
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return subscriptionId;
}
public void updateSubscription(Subscription subscription) throws BillingException {
boolean successful = false;
try {
dataAccessObject.beginTransaction();
dataAccessObject.updateSubscription(subscription);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
}
public int addPayment(Payment payment) throws BillingException {
boolean successful = false;
int paymentId = 0;
try {
dataAccessObject.beginTransaction();
paymentId = dataAccessObject.addPayment(payment);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return paymentId;
}
public Invoice getLastInvoice(Customer customer) throws BillingException {
boolean successful = false;
Invoice invoice = null;
try {
dataAccessObject.beginTransaction();
invoice = dataAccessObject.getLastInvoice(customer);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return invoice;
}
public List<Invoice> getAllInvoices(Customer customer) throws BillingException {
boolean successful = false;
List<Invoice> invoices = null;
try {
dataAccessObject.beginTransaction();
invoices = dataAccessObject.getAllInvoices(customer);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return invoices;
}
public List<Subscription> getActiveSubscriptions(Customer customer) throws BillingException {
boolean successful = false;
List<Subscription> subscriptions;
try {
dataAccessObject.beginTransaction();
subscriptions =
dataAccessObject.getFilteredActiveSubscriptionsForCustomer(
billingTaskConfig.getSubscriptionFilter(), customer);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return subscriptions;
}
public Subscription getActiveSubscriptionOfCustomer(int customerId) throws BillingException {
boolean successful = false;
Subscription subscription;
try {
dataAccessObject.beginTransaction();
subscription =
dataAccessObject.getActiveSubscriptionOfCustomer(customerId);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return subscription;
}
public List<Invoice> getInvoices(Customer customer) throws BillingException {
boolean successful = false;
List<Invoice> invoices;
try {
dataAccessObject.beginTransaction();
invoices = dataAccessObject.getInvoices(customer);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return invoices;
}
public Invoice getInvoice(int invoiceId) throws BillingException {
boolean successful = false;
Invoice invoice = null;
try {
dataAccessObject.beginTransaction();
invoice = dataAccessObject.getInvoice(invoiceId);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return invoice;
}
public List<Item> getBilledItems(Subscription subscription) throws BillingException {
boolean successful = false;
List<Item> billedItems;
try {
dataAccessObject.beginTransaction();
billedItems = dataAccessObject.getBilledItems(subscription);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return billedItems;
}
public List<Subscription> getInvoiceSubscriptions(int invoiceId) throws BillingException {
boolean successful = false;
List<Subscription> subscriptions;
try {
dataAccessObject.beginTransaction();
subscriptions = dataAccessObject.getInvoiceSubscriptions(invoiceId);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return subscriptions;
}
public Payment getLastPayment(Customer customer) throws BillingException {
boolean successful = false;
Payment payment;
try {
dataAccessObject.beginTransaction();
payment = dataAccessObject.getLastPayment(customer);
successful = true;
} finally {
if (successful) {
dataAccessObject.commitTransaction();
} else {
dataAccessObject.rollbackTransaction();
}
}
return payment;
}
public List<Customer> getAllCustomers() throws BillingException {
return CustomerUtils.getAllCustomers();
}
public List<OutstandingBalanceInfoBean> getAllOutstandingBalanceInfoBeans(String tenantDomain)
throws BillingException {
if(tenantDomain==null || "".equals(tenantDomain)){
return getAllOutstandingBalances(null);
}else{
List<Customer> customers = getCustomersWithName(tenantDomain);
if(customers!=null && customers.size()>0){
return getAllOutstandingBalances(customers.get(0));
}else{
return new ArrayList<OutstandingBalanceInfoBean>();
}
}
}
public List<OutstandingBalanceInfoBean> getAllOutstandingBalances(Customer preferredCustomer) throws BillingException{
List<Customer> customers;// = getAllCustomers();
List<OutstandingBalanceInfoBean> outstandingBalances = new ArrayList<OutstandingBalanceInfoBean>();
if(preferredCustomer!=null){
customers = new ArrayList<Customer>();
customers.add(preferredCustomer);
}else{
customers = getAllCustomers();
}
for(Customer customer : customers){
OutstandingBalanceInfoBean balanceBean = new OutstandingBalanceInfoBean();
balanceBean.setCustomerName(customer.getName());
Invoice invoice = getLastInvoice(customer);
if(invoice!=null){
balanceBean.setCarriedForward(invoice.getCarriedForward().toString());
balanceBean.setLastInvoiceDate(invoice.getDate());
List<Subscription> subscriptions = getInvoiceSubscriptions(invoice.getId());
if(subscriptions!=null && subscriptions.size()>0){
balanceBean.setSubscription(subscriptions.get(0).getSubscriptionPlan());
}
}else{ //if we dont have an invoice we have to look for the active subscription to get the subscription plan
Subscription subscription = getActiveSubscriptionOfCustomer(customer.getId());
if(subscription!=null){
balanceBean.setSubscription(subscription.getSubscriptionPlan());
}else{
balanceBean.setSubscription("Not Available");
}
}
Payment payment = getLastPayment(customer);
if(payment!=null){
balanceBean.setLastPaidAmount(payment.getAmount().toString());
balanceBean.setLastPaymentDate(payment.getDate());
}
outstandingBalances.add(balanceBean);
}
return outstandingBalances;
}
public void sendPaymentReceivedEmail(String toAddress, String emailFile,
Map<String,String> mailParameters) throws Exception {
String emailTemplateFile = CarbonUtils.getCarbonConfigDirPath() + "/" + emailFile;
EmailSenderConfiguration senderConfiguration =
EmailSenderConfiguration.loadEmailSenderConfiguration(emailTemplateFile);
EmailSender sender = new EmailSender(senderConfiguration);
sender.sendEmail(toAddress, mailParameters);
}
}