package service; import api.v1.ForecastSearchResult; import api.v1.InvoiceData; import com.avaje.ebean.Ebean; import exceptions.PoseidonException; import models.*; import org.joda.time.DateTime; import play.mvc.Http; import java.text.SimpleDateFormat; import java.util.*; public class InvoiceGeneratorService extends PoseidonService { private ProductModel defaultProduct ; private final ProductModel oppstartsgebyrProduct; public InvoiceGeneratorService(String user) { super(user); defaultProduct = ProductModel.findByName("Offshore by MET.no"); if ( defaultProduct == null) { throw new PoseidonException(Http.Status.INTERNAL_SERVER_ERROR,"Fant ikke default produkt"); } oppstartsgebyrProduct = ProductModel.findBySku("oppstart"); if ( oppstartsgebyrProduct == null) { throw new PoseidonException(Http.Status.INTERNAL_SERVER_ERROR,"Fant ikke produkt for oppstartgebyr"); } } public String generateInvoice(List<InvoiceLine> invoiceData) { String CSV_COLUMN_HEADER = "BRUDD\tFORETAK\tRESKNR\tPERIODE\tBILDATO\tFORDATO\tBETBET\tVARREF\tKUNREF\tORDRE\tVARENR\tTEKST\tLKTODEL2\tLKTODEL3\tLKTODEL6\tVALKODE\tANTALL\tSATS\tBELOP\tAVGKODE\n"; StringBuilder builder = new StringBuilder(CSV_COLUMN_HEADER); for (InvoiceLine invoiceLine : invoiceData) { builder .append(invoiceLine.brudd).append("\t") .append(invoiceLine.foretak).append("\t") .append(invoiceLine.resknr).append("\t") .append(invoiceLine.periode).append("\t") .append(invoiceLine.bildato).append("\t") .append("").append("\t") // fordato .append("").append("\t") // betbet .append(invoiceLine.varref).append("\t") .append(invoiceLine.kunref).append("\t") .append(invoiceLine.ordre).append("\t") .append(invoiceLine.varenr).append("\t") .append(invoiceLine.tekst).append("\t") .append(invoiceLine.lktodel2).append("\t") .append(invoiceLine.lktodel3).append("\t") .append("").append("\t") // lktodel6 .append("").append("\t") // valkode .append(invoiceLine.antall).append("\t") .append(invoiceLine.sats).append("\n"); } return builder.toString(); } public List<InvoiceLine> generateInvoiceLines(InvoiceData data, String ourReference) { StandardAccountModel k2 = StandardAccountModel.findByName("K2"); StandardAccountModel k3 = StandardAccountModel.findByName("K3"); String varenr = PoseidonPropertyService.getProperty("invoicing.varenr"); int oppstartsgebyr = oppstartsgebyrProduct.price; SimpleDateFormat sdfPeriode = new SimpleDateFormat("yyMM"); SimpleDateFormat sdfBilldate = new SimpleDateFormat("yyyyddMM"); DateTime now = getNow(); String periode = sdfPeriode.format(now.toDate()); String bildato = sdfBilldate.format(now.toDate()); String varref = ourReference; Map<String, InvoiceableCustomer> customerMap = mapForecastsToCustomersAndOrders(data); List<InvoiceLine> result = mapCustomerOrderForecastsToInvoiceLines(customerMap, oppstartsgebyr, periode, bildato, varref,varenr, k2,k3); return result; } private Map<String, InvoiceableCustomer> mapForecastsToCustomersAndOrders(InvoiceData data) { Map<String, InvoiceableCustomer> result = new HashMap<>(); for (ForecastSearchResult forecast : data.forecasts) { OrderModel order = OrderModel.findByMetref(forecast.met_ref); String customerNumber = order.customer.customer_number; if ( customerNumber == null) continue; // ignorer kunder uten kundenummer InvoiceableCustomer customer; if (result.containsKey(customerNumber)) { // customer exists in map customer = result.get(customerNumber); Map<String, InvoiceableOrder> orders = customer.orders; InvoiceableOrder invoiceableOrder; if (orders.containsKey(order.met_ref)) { invoiceableOrder = orders.get(order.met_ref); } else { invoiceableOrder = new InvoiceableOrder(order); orders.put(order.met_ref, invoiceableOrder); } invoiceableOrder.producedForecasts = forecast.produced_forecasts; invoiceableOrder.start = forecast.start_date; invoiceableOrder.end = forecast.end_date; } else { customer = new InvoiceableCustomer(customerNumber); result.put(customerNumber, customer); InvoiceableOrder invoiceableOrder = new InvoiceableOrder(order); invoiceableOrder.producedForecasts = forecast.produced_forecasts; invoiceableOrder.start = forecast.start_date; invoiceableOrder.end = forecast.end_date; customer.orders.put(order.met_ref,invoiceableOrder); } } return result; } private List<InvoiceLine> mapCustomerOrderForecastsToInvoiceLines(Map<String, InvoiceableCustomer> customerMap, int oppstartsgebyr, String periode, String bildato, String varref, String varenr, StandardAccountModel k2, StandardAccountModel k3) { List<InvoiceLine> result = new ArrayList<>(); for (String customerNumber : customerMap.keySet()) { InvoiceableCustomer customer = customerMap.get(customerNumber); for (String met_ref : customer.orders.keySet()) { InvoiceableOrder invoiceableOrder = customer.orders.get(met_ref); if (invoiceableOrder != null) { int antallVarsel = invoiceableOrder.producedForecasts ; OrderModel order = invoiceableOrder.orderModel; result.add(getReminderLine(order, periode, bildato, varref)); if (order.startup_fee) { result.add(getStartupFeeLine(order, periode, bildato, varref, oppstartsgebyr,varenr,k2,k3)); } String pNavn = order.position_name != null && !order.position_name.isEmpty() ? order.position_name : order.position.name; String tekst = getTekstFakturalinje(pNavn, invoiceableOrder); result.add(getForecastFeeLine(order, periode, bildato, varref, tekst, antallVarsel,varenr,k2,k3)); } } } return result; } private String getTekstFakturalinje(String positionName,InvoiceableOrder order) { SimpleDateFormat sdf = new SimpleDateFormat("yyMM"); return "Varsel for " + positionName + " fom. " + sdf.format(order.start) + " tom. " + sdf.format(order.end); } private InvoiceLine getReminderLine(OrderModel order, String periode, String bildato, String varref) { InvoiceLine line = new InvoiceLine(); line.resknr = order.customer.customer_number; line.periode = periode; line.bildato = bildato; line.varref = varref; line.kunref = order.custref_po_calloff; line.ordre = order.met_ref; line.varenr = "T"; line.lktodel2 = ""; line.lktodel3 = ""; line.tekst = "Vær vennlig å oppgi fakturanummer ved betaling"; line.antall = 1; return line; } private InvoiceLine getStartupFeeLine(OrderModel order, String periode, String bildato, String varref, int oppstartsgebyr, String varenr, StandardAccountModel k2, StandardAccountModel k3) { InvoiceLine line = new InvoiceLine(); line.resknr = order.customer.customer_number; line.periode = periode; line.bildato = bildato; line.varref = varref; line.varenr = varenr; line.kunref = order.custref_po_calloff; line.ordre = order.met_ref; line.lktodel2 = k2.account; line.lktodel3 = k3.account; line.antall = 1; line.tekst ="Oppstartsgebyr"; line.sats = oppstartsgebyr; return line; } private InvoiceLine getForecastFeeLine(OrderModel order, String periode, String bildato, String varref, String tekst, int antallVarsel, String varenr, StandardAccountModel k2, StandardAccountModel k3) { InvoiceLine line = new InvoiceLine(); line.resknr = order.customer.customer_number; line.periode = periode; line.bildato = bildato; line.varref = varref; line.varenr = varenr; line.kunref = order.custref_po_calloff; line.ordre = order.met_ref; line.lktodel2 = k2.account; line.lktodel3 = k3.account; line.tekst = tekst; if ( order.product != null ) { line.sats = order.product.price; } else { line.sats = defaultProduct.price; } line.antall = antallVarsel; return line; } public void markForecastsAsBilled(ForecastSearchResult[] forecasts) { for (int i = 0; i < forecasts.length; i++) { ForecastSearchResult forecast = forecasts[i]; List<ForecastModel> forecastModels = ForecastModel.findByMetrefAndDateRange(forecast.met_ref, forecast.start_date, forecast.end_date); for (ForecastModel forecastModel : forecastModels) { forecastModel.invoiced = true; forecastModel.updated = getNow().toDate(); forecastModel.updatedBy = getUser(); Ebean.update(forecastModel); } } } private class InvoiceableCustomer { public String customerNumber; public Map<String, InvoiceableOrder> orders = new HashMap<>(); public InvoiceableCustomer(String customerNumber) { this.customerNumber = customerNumber; } } private class InvoiceableOrder { public OrderModel orderModel; public int producedForecasts; public Date start; public Date end; public InvoiceableOrder(OrderModel orderModel) { this.orderModel = orderModel; } } }