0001: /*
0002: * $Id: InvoiceServices.java,v 1.8 2004/01/22 17:47:24 ajzeneski Exp $
0003: *
0004: * Copyright (c) 2003 The Open For Business Project - www.ofbiz.org
0005: *
0006: * Permission is hereby granted, free of charge, to any person obtaining a
0007: * copy of this software and associated documentation files (the "Software"),
0008: * to deal in the Software without restriction, including without limitation
0009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0010: * and/or sell copies of the Software, and to permit persons to whom the
0011: * Software is furnished to do so, subject to the following conditions:
0012: *
0013: * The above copyright notice and this permission notice shall be included
0014: * in all copies or substantial portions of the Software.
0015: *
0016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
0020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
0021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
0022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0023: */
0024: package org.ofbiz.accounting.invoice;
0025:
0026: import java.util.ArrayList;
0027: import java.util.HashMap;
0028: import java.util.Iterator;
0029: import java.util.LinkedList;
0030: import java.util.List;
0031: import java.util.Map;
0032: import java.util.Set;
0033:
0034: import org.ofbiz.accounting.payment.PaymentWorker;
0035: import org.ofbiz.base.util.Debug;
0036: import org.ofbiz.base.util.UtilDateTime;
0037: import org.ofbiz.base.util.UtilMisc;
0038: import org.ofbiz.entity.GenericDelegator;
0039: import org.ofbiz.entity.GenericEntityException;
0040: import org.ofbiz.entity.GenericValue;
0041: import org.ofbiz.order.order.OrderReadHelper;
0042: import org.ofbiz.service.DispatchContext;
0043: import org.ofbiz.service.GenericServiceException;
0044: import org.ofbiz.service.LocalDispatcher;
0045: import org.ofbiz.service.ServiceUtil;
0046: import org.ofbiz.product.product.ProductWorker;
0047:
0048: /**
0049: * InvoiceServices - Services for creating invoices
0050: *
0051: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
0052: * @version $Revision: 1.8 $
0053: * @since 2.2
0054: */
0055: public class InvoiceServices {
0056:
0057: public static String module = InvoiceServices.class.getName();
0058:
0059: /* Service to create an invoice for an order */
0060: public static Map createInvoiceForOrder(DispatchContext dctx,
0061: Map context) {
0062: GenericDelegator delegator = dctx.getDelegator();
0063: LocalDispatcher dispatcher = dctx.getDispatcher();
0064: GenericValue userLogin = (GenericValue) context
0065: .get("userLogin");
0066:
0067: String orderId = (String) context.get("orderId");
0068: List billItems = (List) context.get("billItems");
0069: boolean previousInvoiceFound = false;
0070:
0071: if (billItems == null || billItems.size() == 0) {
0072: Debug
0073: .logVerbose(
0074: "No items to invoice; not creating; returning success",
0075: module);
0076: return ServiceUtil.returnSuccess();
0077: }
0078:
0079: List toStore = new LinkedList();
0080: GenericValue orderHeader = null;
0081: try {
0082: orderHeader = delegator.findByPrimaryKey("OrderHeader",
0083: UtilMisc.toMap("orderId", orderId));
0084: } catch (GenericEntityException e) {
0085: Debug.logError(e, "Cannot get order header", module);
0086: }
0087:
0088: if (orderHeader == null) {
0089: return ServiceUtil
0090: .returnError("No OrderHeader, cannot create invoice");
0091: }
0092:
0093: // get list of previous invoices for the order
0094: List billedItems = null;
0095: try {
0096: billedItems = delegator.findByAnd("OrderItemBilling",
0097: UtilMisc.toMap("orderId", orderId));
0098: } catch (GenericEntityException e) {
0099: Debug.logError(e, "Cannot looking billed items", module);
0100: return ServiceUtil
0101: .returnError("Unable to looked previous billed items");
0102: }
0103: if (billedItems != null && billedItems.size() > 0) {
0104: boolean nonDigitalInvoice = false;
0105: Iterator bii = billedItems.iterator();
0106: while (bii.hasNext() && !nonDigitalInvoice) {
0107: GenericValue orderItemBilling = (GenericValue) bii
0108: .next();
0109: GenericValue invoiceItem = null;
0110: try {
0111: invoiceItem = orderItemBilling
0112: .getRelatedOne("InvoiceItem");
0113: } catch (GenericEntityException e) {
0114: Debug
0115: .logError(
0116: e,
0117: "Cannot get InvoiceItem from billing record; assuming non-digital.",
0118: module);
0119: nonDigitalInvoice = true;
0120: }
0121: if (invoiceItem != null) {
0122: String invoiceItemType = invoiceItem
0123: .getString("invoiceItemTypeId");
0124: if (invoiceItemType != null) {
0125: if ("INV_FPROD_ITEM".equals(invoiceItemType)
0126: || "INV_PROD_FEATR_ITEM"
0127: .equals(invoiceItemType)) {
0128: nonDigitalInvoice = true;
0129: }
0130: }
0131: }
0132: }
0133: if (nonDigitalInvoice) {
0134: previousInvoiceFound = true;
0135: }
0136: }
0137:
0138: // figure out the invoice type
0139: String invoiceType = null;
0140:
0141: String orderType = orderHeader.getString("orderTypeId");
0142: if (orderType.equals("SALES_ORDER")) {
0143: invoiceType = "SALES_INVOICE";
0144: } else if (orderType.equals("PURCHASE_ORDER")) {
0145: invoiceType = "PURCHASE_INVOICE";
0146: }
0147:
0148: OrderReadHelper orh = new OrderReadHelper(orderHeader);
0149:
0150: // get the product store
0151: GenericValue productStore = null;
0152: try {
0153: productStore = delegator.findByPrimaryKey("ProductStore",
0154: UtilMisc.toMap("productStoreId", orh
0155: .getProductStoreId()));
0156: } catch (GenericEntityException e) {
0157: Debug.logError(e, "Unable to get ProductStore", module);
0158: return ServiceUtil
0159: .returnError("Unable to get Product Store from order");
0160: }
0161:
0162: // get the payToParty
0163: String payToPartyId = productStore.getString("payToPartyId");
0164: if (payToPartyId == null) {
0165: return ServiceUtil
0166: .returnError("Unable to create invoice; no payToPartyId set for ProductStore Id : "
0167: + orh.getProductStoreId());
0168: }
0169:
0170: // get some quantity totals
0171: double totalItemsInOrder = orh.getTotalOrderItemsQuantity();
0172:
0173: // get some price totals
0174: double shippableAmount = orh.getShippableTotal();
0175: double orderSubTotal = orh.getOrderItemsSubTotal();
0176:
0177: double invoiceShipProRateAmount = 0.00;
0178: double invoiceSubTotal = 0.00;
0179: double invoiceQuantity = 0.00;
0180:
0181: // create the invoice record
0182: String invoiceId = delegator.getNextSeqId("Invoice").toString();
0183: GenericValue invoice = delegator.makeValue("Invoice", UtilMisc
0184: .toMap("invoiceId", invoiceId));
0185: invoice.set("invoiceDate", UtilDateTime.nowTimestamp());
0186: invoice.set("invoiceTypeId", invoiceType);
0187: invoice.set("statusId", "INVOICE_READY");
0188:
0189: GenericValue billingAccount = null;
0190: List billingAccountTerms = null;
0191: try {
0192: billingAccount = orderHeader
0193: .getRelatedOne("BillingAccount");
0194: } catch (GenericEntityException e) {
0195: Debug
0196: .logError(
0197: e,
0198: "Trouble getting BillingAccount entity from OrderHeader",
0199: module);
0200: ServiceUtil
0201: .returnError("Trouble getting BillingAccount entity from OrderHeader");
0202: }
0203:
0204: // for billing accounts we will use related information
0205: if (billingAccount != null) {
0206: // set the billing account
0207: invoice.set("billingAccountId", billingAccount
0208: .getString("billingAccountId"));
0209:
0210: // get the billing account terms
0211: try {
0212: billingAccountTerms = billingAccount
0213: .getRelated("BillingAccountTerm");
0214: } catch (GenericEntityException e) {
0215: Debug
0216: .logError(
0217: e,
0218: "Trouble getting BillingAccountTerm entity list",
0219: module);
0220: ServiceUtil
0221: .returnError("Trouble getting BillingAccountTerm entity list");
0222: }
0223:
0224: // set the invoice terms as defined for the billing account
0225: if (billingAccountTerms != null) {
0226: Iterator billingAcctTermsIter = billingAccountTerms
0227: .iterator();
0228: while (billingAcctTermsIter.hasNext()) {
0229: GenericValue term = (GenericValue) billingAcctTermsIter
0230: .next();
0231: GenericValue invoiceTerm = delegator.makeValue(
0232: "InvoiceTerm", UtilMisc.toMap("invoiceId",
0233: invoiceId, "invoiceItemSeqId",
0234: "_NA_"));
0235: invoiceTerm.set("termType", term.get("termType"));
0236: invoiceTerm.set("termValue", term.get("termValue"));
0237: invoiceTerm.set("uomId", term.get("uomId"));
0238: toStore.add(invoiceTerm);
0239: }
0240: }
0241:
0242: // set the invoice bill_to_customer from the billing account
0243: List billToRoles = null;
0244: try {
0245: billToRoles = billingAccount
0246: .getRelated("BillingAccountRole",
0247: UtilMisc.toMap("roleTypeId",
0248: "BILL_TO_CUSTOMER"), null);
0249: } catch (GenericEntityException e) {
0250: Debug
0251: .logError(
0252: e,
0253: "Trouble getting BillingAccountRole entity list",
0254: module);
0255: ServiceUtil
0256: .returnError("Trouble getting BillingAccountRole entity list");
0257: }
0258: Iterator billToIter = billToRoles.iterator();
0259: while (billToIter.hasNext()) {
0260: GenericValue billToRole = (GenericValue) billToIter
0261: .next();
0262: GenericValue invoiceRole = delegator.makeValue(
0263: "InvoiceRole", UtilMisc.toMap("invoiceId",
0264: invoiceId));
0265: invoiceRole.set("partyId", billToRole.get("partyId"));
0266: invoiceRole.set("roleTypeId", "BILL_TO_CUSTOMER");
0267: toStore.add(invoiceRole);
0268: }
0269:
0270: // set the bill-to contact mech as the contact mech of the billing account
0271: GenericValue billToContactMech = delegator.makeValue(
0272: "InvoiceContactMech", UtilMisc.toMap("invoiceId",
0273: invoiceId));
0274: billToContactMech.set("contactMechId", billingAccount
0275: .getString("contactMechId"));
0276: billToContactMech.set("contactMechPurposeTypeId",
0277: "BILLING_LOCATION");
0278: toStore.add(billToContactMech);
0279: } else {
0280: // no billing account use the info off the order header
0281: GenericValue billToPerson = orh.getBillToPerson();
0282: if (billToPerson != null) {
0283: GenericValue invoiceRole = delegator.makeValue(
0284: "InvoiceRole", UtilMisc.toMap("invoiceId",
0285: invoiceId));
0286: invoiceRole.set("partyId", billToPerson
0287: .getString("partyId"));
0288: invoiceRole.set("roleTypeId", "BILL_TO_CUSTOMER");
0289: toStore.add(invoiceRole);
0290: }
0291:
0292: GenericValue billingAddress = orh.getBillingAddress();
0293: if (billingAddress != null) {
0294: GenericValue billToContactMech = delegator.makeValue(
0295: "InvoiceContactMech", UtilMisc.toMap(
0296: "invoiceId", invoiceId));
0297: billToContactMech.set("contactMechId", billingAddress
0298: .getString("contactMechId"));
0299: billToContactMech.set("contactMechPurposeTypeId",
0300: "BILLING_LOCATION");
0301: toStore.add(billToContactMech);
0302: }
0303: }
0304:
0305: // store the invoice first
0306: try {
0307: delegator.create(invoice);
0308: } catch (GenericEntityException e) {
0309: Debug.logError(e, "Cannot create invoice record", module);
0310: ServiceUtil.returnError("Problems storing Invoice record");
0311: }
0312:
0313: // get a list of the payment method types
0314: List paymentPreferences = null;
0315: try {
0316: paymentPreferences = orderHeader
0317: .getRelated("OrderPaymentPreference");
0318: } catch (GenericEntityException e) {
0319: Debug
0320: .logError(
0321: e,
0322: "Trouble getting OrderPaymentPreference entity list",
0323: module);
0324: }
0325:
0326: // create the bill-from role BILL_FROM_VENDOR as the partyId for the store
0327: GenericValue payToRole = delegator.makeValue("InvoiceRole",
0328: UtilMisc.toMap("invoiceId", invoiceId));
0329: payToRole.set("partyId", payToPartyId);
0330: payToRole.set("roleTypeId", "BILL_FROM_VENDOR");
0331: toStore.add(payToRole);
0332:
0333: // create the bill-from (or pay-to) contact mech as the primary PAYMENT_LOCATION of the party from the store
0334: GenericValue payToAddress = PaymentWorker.getPaymentAddress(
0335: delegator, payToPartyId);
0336: if (payToAddress != null) {
0337: GenericValue payToCm = delegator.makeValue(
0338: "InvoiceContactMech", UtilMisc.toMap("invoiceId",
0339: invoiceId));
0340: payToCm.set("contactMechId", payToAddress
0341: .getString("contactMechId"));
0342: payToCm.set("contactMechPurposeTypeId", "PAYMENT_LOCATION");
0343: toStore.add(payToCm);
0344: }
0345:
0346: // sequence for items - all OrderItems or InventoryReservations + all Adjustments
0347: int itemSeqId = 1;
0348:
0349: // create the item records
0350: if (billItems != null) {
0351: Iterator itemIter = billItems.iterator();
0352: while (itemIter.hasNext()) {
0353: GenericValue itemIssuance = null;
0354: GenericValue orderItem = null;
0355: GenericValue currentValue = (GenericValue) itemIter
0356: .next();
0357: if ("ItemIssuance".equals(currentValue.getEntityName())) {
0358: itemIssuance = currentValue;
0359: } else if ("OrderItem".equals(currentValue
0360: .getEntityName())) {
0361: orderItem = currentValue;
0362: }
0363:
0364: if (orderItem == null && itemIssuance != null) {
0365: try {
0366: orderItem = itemIssuance
0367: .getRelatedOne("OrderItem");
0368: } catch (GenericEntityException e) {
0369: Debug
0370: .logError(
0371: e,
0372: "Trouble getting related OrderItem from ItemIssuance",
0373: module);
0374: return ServiceUtil
0375: .returnError("Trouble getting OrderItem from ItemIssuance");
0376: }
0377: } else if (orderItem == null && itemIssuance == null) {
0378: Debug
0379: .logError(
0380: "Cannot create invoice when both orderItem and itemIssuance is null",
0381: module);
0382: return ServiceUtil
0383: .returnError("Illegal values passed to create invoice service");
0384: }
0385: GenericValue product = null;
0386: if (orderItem.get("productId") != null) {
0387: try {
0388: product = orderItem.getRelatedOne("Product");
0389: } catch (GenericEntityException e) {
0390: Debug
0391: .logError(
0392: e,
0393: "Trouble getting Product from OrderItem",
0394: module);
0395: ServiceUtil
0396: .returnError("Trouble getting Product from OrderItem");
0397: }
0398: }
0399:
0400: // get some quantities
0401: Double orderedQuantity = orderItem
0402: .getDouble("quantity");
0403: Double billingQuantity = null;
0404: if (itemIssuance != null) {
0405: billingQuantity = itemIssuance
0406: .getDouble("quantity");
0407: } else {
0408: billingQuantity = orderedQuantity;
0409: }
0410: if (orderedQuantity == null)
0411: orderedQuantity = new Double(0.00);
0412: if (billingQuantity == null)
0413: billingQuantity = new Double(0.00);
0414:
0415: String lookupType = "FINISHED_GOOD"; // the default product type
0416: if (product != null) {
0417: lookupType = product.getString("productTypeId");
0418: } else if (orderItem != null) {
0419: lookupType = orderItem.getString("orderItemTypeId");
0420: }
0421:
0422: // check if shipping applies to this item
0423: boolean shippingApplies = false;
0424: if (product != null
0425: && ProductWorker.shippingApplies(product)) {
0426: shippingApplies = true;
0427: }
0428:
0429: GenericValue invoiceItem = delegator.makeValue(
0430: "InvoiceItem", UtilMisc.toMap("invoiceId",
0431: invoiceId, "invoiceItemSeqId",
0432: new Integer(itemSeqId).toString()));
0433: invoiceItem.set("invoiceItemTypeId",
0434: getInvoiceItemType(delegator, lookupType,
0435: "INV_FPROD_ITEM"));
0436: invoiceItem.set("description", orderItem
0437: .get("itemDescription"));
0438: invoiceItem.set("quantity", billingQuantity);
0439: invoiceItem.set("amount", orderItem.get("unitPrice"));
0440: invoiceItem
0441: .set("productId", orderItem.get("productId"));
0442: invoiceItem.set("productFeatureId", orderItem
0443: .get("productFeatureId"));
0444: //invoiceItem.set("uomId", "");
0445:
0446: String itemIssuanceId = null;
0447: if (itemIssuance != null
0448: && itemIssuance.get("inventoryItemId") != null) {
0449: itemIssuanceId = itemIssuance
0450: .getString("itemIssuanceId");
0451: invoiceItem.set("inventoryItemId", itemIssuance
0452: .get("inventoryItemId"));
0453: }
0454: if (product != null) {
0455: invoiceItem.set("taxableFlag", product
0456: .get("taxable"));
0457: }
0458: toStore.add(invoiceItem);
0459:
0460: // this item total
0461: double this Amount = invoiceItem.getDouble("amount")
0462: .doubleValue()
0463: * invoiceItem.getDouble("quantity")
0464: .doubleValue();
0465:
0466: // add to the ship amount only if it applies to this item
0467: if (shippingApplies) {
0468: invoiceShipProRateAmount += this Amount;
0469: }
0470:
0471: // increment the invoice subtotal
0472: invoiceSubTotal += this Amount;
0473:
0474: // increment the invoice quantity
0475: invoiceQuantity += billingQuantity.doubleValue();
0476:
0477: // create the OrderItemBilling record
0478: GenericValue orderItemBill = delegator.makeValue(
0479: "OrderItemBilling", UtilMisc.toMap("invoiceId",
0480: invoiceId, "invoiceItemSeqId",
0481: new Integer(itemSeqId).toString()));
0482: orderItemBill.set("orderId", orderItem.get("orderId"));
0483: orderItemBill.set("orderItemSeqId", orderItem
0484: .get("orderItemSeqId"));
0485: orderItemBill.set("itemIssuanceId", itemIssuanceId);
0486: orderItemBill.set("quantity", invoiceItem
0487: .get("quantity"));
0488: orderItemBill.set("amount", invoiceItem.get("amount"));
0489: toStore.add(orderItemBill);
0490:
0491: // increment the counter
0492: itemSeqId++;
0493:
0494: // create the item adjustment as line items
0495: List itemAdjustments = OrderReadHelper
0496: .getOrderItemAdjustmentList(orderItem, orh
0497: .getAdjustments());
0498: Iterator itemAdjIter = itemAdjustments.iterator();
0499: while (itemAdjIter.hasNext()) {
0500: GenericValue adj = (GenericValue) itemAdjIter
0501: .next();
0502: if (adj.get("amount") != null) {
0503: // pro-rate the amount
0504: double amount = ((adj.getDouble("amount")
0505: .doubleValue() / orderItem.getDouble(
0506: "quantity").doubleValue()) * invoiceItem
0507: .getDouble("quantity").doubleValue());
0508: GenericValue adjInvItem = delegator.makeValue(
0509: "InvoiceItem", UtilMisc.toMap(
0510: "invoiceId", invoiceId,
0511: "invoiceItemSeqId",
0512: new Integer(itemSeqId)
0513: .toString()));
0514: adjInvItem
0515: .set(
0516: "invoiceItemTypeId",
0517: getInvoiceItemType(
0518: delegator,
0519: adj
0520: .getString("orderAdjustmentTypeId"),
0521: "INVOICE_ITM_ADJ"));
0522: adjInvItem.set("productId", orderItem
0523: .get("productId"));
0524: adjInvItem.set("productFeatureId", orderItem
0525: .get("productFeatureId"));
0526: //adjInvItem.set("uomId", "");
0527: adjInvItem.set("taxableFlag", product
0528: .get("taxable"));
0529: adjInvItem.set("quantity", new Double(1));
0530: adjInvItem.set("amount", new Double(amount));
0531: adjInvItem.set("description", adj
0532: .get("description"));
0533: toStore.add(adjInvItem);
0534:
0535: // this adjustment amount
0536: double this AdjAmount = adjInvItem.getDouble(
0537: "amount").doubleValue()
0538: * adjInvItem.getDouble("quantity")
0539: .doubleValue();
0540:
0541: // adjustments only apply to totals when they are not tax or shipping adjustments
0542: if (!"SALES_TAX".equals(adj
0543: .getString("orderAdjustmentTypeId"))
0544: && !"SHIPPING_ADJUSTMENT"
0545: .equals(adj
0546: .getString("orderAdjustmentTypeId"))) {
0547: // increment the invoice subtotal
0548: invoiceSubTotal += this AdjAmount;
0549:
0550: // add to the ship amount only if it applies to this item
0551: if (shippingApplies) {
0552: invoiceShipProRateAmount += this AdjAmount;
0553: }
0554: }
0555:
0556: // increment the counter
0557: itemSeqId++;
0558: }
0559: if (adj.get("percentage") != null
0560: || adj.get("amountPerQuantity") != null) {
0561: Double amountPerQty = adj.getDouble("amount");
0562: Double percent = adj.getDouble("percentage");
0563: double totalAmount = 0.00;
0564: if (percent != null)
0565: totalAmount += percent.doubleValue()
0566: * (invoiceItem.getDouble("amount")
0567: .doubleValue() * invoiceItem
0568: .getDouble("quantity")
0569: .doubleValue());
0570: if (amountPerQty != null)
0571: totalAmount += amountPerQty.doubleValue()
0572: * invoiceItem.getDouble("quantity")
0573: .doubleValue();
0574:
0575: GenericValue adjInvItem = delegator.makeValue(
0576: "InvoiceItem", UtilMisc.toMap(
0577: "invoiceId", invoiceId,
0578: "invoiceItemSeqId",
0579: new Integer(itemSeqId)
0580: .toString()));
0581: adjInvItem
0582: .set(
0583: "invoiceItemTypeId",
0584: getInvoiceItemType(
0585: delegator,
0586: adj
0587: .getString("orderAdjustmentTypeId"),
0588: "INVOICE_ITM_ADJ"));
0589: adjInvItem.set("productId", orderItem
0590: .get("productId"));
0591: adjInvItem.set("productFeatureId", orderItem
0592: .get("productFeatureId"));
0593: //adjInvItem.set("uomId", "");
0594: adjInvItem.set("taxableFlag", product
0595: .get("taxable"));
0596: adjInvItem.set("quantity", orderItem
0597: .getDouble("quantity"));
0598: adjInvItem.set("amount",
0599: new Double(totalAmount));
0600: adjInvItem.set("description", adj
0601: .get("description"));
0602: toStore.add(adjInvItem);
0603:
0604: // this adjustment amount
0605: double this AdjAmount = adjInvItem.getDouble(
0606: "amount").doubleValue()
0607: * adjInvItem.getDouble("quantity")
0608: .doubleValue();
0609:
0610: // adjustments only apply to totals when they are not tax or shipping adjustments
0611: if (!"SALES_TAX".equals(adj
0612: .getString("orderAdjustmentTypeId"))
0613: && !"SHIPPING_ADJUSTMENT"
0614: .equals(adj
0615: .getString("orderAdjustmentTypeId"))) {
0616: // increment the invoice subtotal
0617: invoiceSubTotal += this AdjAmount;
0618:
0619: // add to the ship amount only if it applies to this item
0620: if (shippingApplies) {
0621: invoiceShipProRateAmount += this AdjAmount;
0622: }
0623: }
0624:
0625: // increment the counter
0626: itemSeqId++;
0627: }
0628: }
0629: }
0630: }
0631:
0632: // get the shipping adjustment mode (Y = Pro-Rate; N = First-Invoice)
0633: String prorateShipping = productStore
0634: .getString("prorateShipping");
0635: if (prorateShipping == null) {
0636: prorateShipping = "Y";
0637: }
0638:
0639: // create header adjustments as line items -- always to tax/shipping last
0640: List shipAdjustments = new ArrayList();
0641: List taxAdjustments = new ArrayList();
0642:
0643: List headerAdjustments = orh.getOrderHeaderAdjustments();
0644: Iterator headerAdjIter = headerAdjustments.iterator();
0645: while (headerAdjIter.hasNext()) {
0646: GenericValue adj = (GenericValue) headerAdjIter.next();
0647: if ("SHIPPING_CHARGES".equals(adj
0648: .getString("orderAdjustmentTypeId"))) {
0649: shipAdjustments.add(adj);
0650: } else if ("SALES_TAX".equals(adj
0651: .getString("orderAdjustmentTypeId"))) {
0652: taxAdjustments.add(adj);
0653: } else {
0654: // other adjustment type
0655: double adjAmount = calcHeaderAdj(delegator, adj,
0656: invoiceId, itemSeqId, toStore, orderSubTotal,
0657: invoiceSubTotal, invoiceQuantity);
0658: // these will effect the shipping pro-rate (unless commented)
0659: // invoiceShipProRateAmount += adjAmount;
0660: // do adjustments compound or are they based off subtotal? Here we will (unless commented)
0661: // invoiceSubTotal += adjAmount;
0662:
0663: // increment the counter
0664: itemSeqId++;
0665: }
0666: }
0667:
0668: // next do the shipping adjustments
0669: Iterator shipAdjIter = shipAdjustments.iterator();
0670: while (shipAdjIter.hasNext()) {
0671: GenericValue adj = (GenericValue) shipAdjIter.next();
0672: if ("N".equalsIgnoreCase(prorateShipping)) {
0673: if (previousInvoiceFound) {
0674: Debug.logInfo(
0675: "Previous invoice found for this order ["
0676: + orderId
0677: + "]; shipping already billed",
0678: module);
0679: continue;
0680: } else {
0681: // this is the first invoice; bill it all now
0682: double adjAmount = calcHeaderAdj(delegator, adj,
0683: invoiceId, itemSeqId, toStore, 1, 1,
0684: totalItemsInOrder);
0685: // should shipping effect the tax pro-rate?
0686: invoiceSubTotal += adjAmount; // here we do
0687:
0688: // increment the counter
0689: itemSeqId++;
0690: }
0691: } else {
0692: // pro-rate the shipping amount based on shippable information
0693: double adjAmount = calcHeaderAdj(delegator, adj,
0694: invoiceId, itemSeqId, toStore, shippableAmount,
0695: invoiceShipProRateAmount, invoiceQuantity);
0696: // should shipping effect the tax pro-rate?
0697: invoiceSubTotal += adjAmount; // here we do
0698:
0699: // increment the counter
0700: itemSeqId++;
0701: }
0702: }
0703:
0704: // last do the tax adjustments
0705: Iterator taxAdjIter = taxAdjustments.iterator();
0706: while (taxAdjIter.hasNext()) {
0707: GenericValue adj = (GenericValue) taxAdjIter.next();
0708: double adjAmount = calcHeaderAdj(delegator, adj, invoiceId,
0709: itemSeqId, toStore, orderSubTotal, invoiceSubTotal,
0710: invoiceQuantity);
0711: // this doesn't really effect anything; but just for our totals
0712: invoiceSubTotal += adjAmount;
0713: }
0714:
0715: // invoice status object
0716: GenericValue invStatus = delegator.makeValue("InvoiceStatus",
0717: UtilMisc.toMap("invoiceId", invoiceId, "statusId",
0718: "INVOICE_IN_PROCESS", "statusDate",
0719: UtilDateTime.nowTimestamp()));
0720: toStore.add(invStatus);
0721:
0722: // check for previous order payments
0723: List orderPaymentPrefs = null;
0724: try {
0725: orderPaymentPrefs = delegator.findByAnd(
0726: "OrderPaymentPreference", UtilMisc.toMap("orderId",
0727: orderId));
0728: } catch (GenericEntityException e) {
0729: Debug.logError(e,
0730: "Problem getting order payment preference records",
0731: module);
0732: return ServiceUtil
0733: .returnError("Problem getting order payment preference records");
0734: }
0735: if (orderPaymentPrefs != null) {
0736: List currentPayments = new ArrayList();
0737: Iterator opi = orderPaymentPrefs.iterator();
0738: while (opi.hasNext()) {
0739: GenericValue paymentPref = (GenericValue) opi.next();
0740: try {
0741: List payments = paymentPref.getRelated("Payment");
0742: currentPayments.addAll(payments);
0743: } catch (GenericEntityException e) {
0744: Debug.logError(e,
0745: "Problem getting payments from preference",
0746: module);
0747: return ServiceUtil
0748: .returnError("Problem getting payments from preference");
0749: }
0750: }
0751: if (currentPayments.size() > 0) {
0752: // apply these payments to the invoice; only if they haven't already been applied
0753: Iterator cpi = currentPayments.iterator();
0754: while (cpi.hasNext()) {
0755: GenericValue payment = (GenericValue) cpi.next();
0756: List currentApplications = null;
0757: try {
0758: currentApplications = payment
0759: .getRelated("PaymentApplication");
0760: } catch (GenericEntityException e) {
0761: Debug
0762: .logError(
0763: e,
0764: "Problem getting application(s) for payment",
0765: module);
0766: return ServiceUtil
0767: .returnError("Problem getting application(s) for payment");
0768: }
0769: if (currentApplications == null
0770: || currentApplications.size() == 0) {
0771: // no applications; okay to apply
0772: String applId = delegator.getNextSeqId(
0773: "PaymentApplication").toString();
0774: GenericValue appl = delegator
0775: .makeValue("PaymentApplication",
0776: UtilMisc.toMap(
0777: "paymentApplicationId",
0778: applId));
0779: appl.set("paymentId", payment.get("paymentId"));
0780: appl.set("invoiceId", invoice.get("invoiceId"));
0781: appl.set("billingAccountId", invoice
0782: .get("billingAccountId"));
0783: appl
0784: .set("amountApplied", payment
0785: .get("amount"));
0786: toStore.add(appl);
0787: }
0788: }
0789: }
0790: }
0791:
0792: // store value objects
0793: try {
0794: //Debug.log("Storing : " + toStore, module);
0795: delegator.storeAll(toStore);
0796: } catch (GenericEntityException e) {
0797: Debug.logError(e, "Problems storing invoice items", module);
0798: return ServiceUtil
0799: .returnError("Cannot create invoice; problem storing items");
0800: }
0801:
0802: // check to see if we are all paid up
0803: Map checkResp = null;
0804: try {
0805: checkResp = dispatcher.runSync(
0806: "checkInvoicePaymentApplications", UtilMisc.toMap(
0807: "invoiceId", invoice.get("invoiceId"),
0808: "userLogin", userLogin));
0809: } catch (GenericServiceException e) {
0810: Debug.logError(e, "Problem checking payment applications",
0811: module);
0812: return ServiceUtil
0813: .returnError("Problem checking payment applications");
0814: }
0815:
0816: Map resp = ServiceUtil.returnSuccess();
0817: resp.put("invoiceId", invoiceId);
0818: return resp;
0819: }
0820:
0821: public static Map createInvoicesFromShipment(DispatchContext dctx,
0822: Map context) {
0823: GenericDelegator delegator = dctx.getDelegator();
0824: LocalDispatcher dispatcher = dctx.getDispatcher();
0825: String shipmentId = (String) context.get("shipmentId");
0826:
0827: List invoicesCreated = new ArrayList();
0828:
0829: GenericValue shipment = null;
0830: try {
0831: shipment = delegator.findByPrimaryKey("Shipment", UtilMisc
0832: .toMap("shipmentId", shipmentId));
0833: } catch (GenericEntityException e) {
0834: Debug
0835: .logError(e, "Trouble getting Shipment entity",
0836: module);
0837: return ServiceUtil
0838: .returnError("Trouble getting Shipment entity");
0839: }
0840:
0841: // check the status of the shipment
0842:
0843: // get the issued items
0844: List itemsIssued = null;
0845: try {
0846: itemsIssued = delegator.findByAnd("ItemIssuance", UtilMisc
0847: .toMap("shipmentId", shipmentId));
0848: } catch (GenericEntityException e) {
0849: Debug.logError(e,
0850: "Problem getting issued items from Shipment",
0851: module);
0852: return ServiceUtil
0853: .returnError("Problem getting issued items from Shipment");
0854: }
0855: if (itemsIssued == null) {
0856: Debug.logInfo("No items issued for shipment", module);
0857: return ServiceUtil.returnSuccess();
0858: }
0859:
0860: // group items by order
0861: Map shippedOrderItems = new HashMap();
0862: Iterator itemsIter = itemsIssued.iterator();
0863: while (itemsIter.hasNext()) {
0864: GenericValue itemIssuance = (GenericValue) itemsIter.next();
0865: String itemIssuanceId = itemIssuance
0866: .getString("itemIssuanceId");
0867: String orderId = itemIssuance.getString("orderId");
0868: String orderItemSeqId = itemIssuance
0869: .getString("orderItemSeqId");
0870: List itemsByOrder = (List) shippedOrderItems.get(orderId);
0871: if (itemsByOrder == null) {
0872: itemsByOrder = new ArrayList();
0873: }
0874:
0875: // check and make sure we haven't already billed for this issuance
0876: Map billFields = UtilMisc.toMap("orderId", orderId,
0877: "orderItemSeqId", orderItemSeqId, "itemIssuanceId",
0878: itemIssuanceId);
0879: List itemBillings = null;
0880: try {
0881: itemBillings = delegator.findByAnd("OrderItemBilling",
0882: billFields);
0883: } catch (GenericEntityException e) {
0884: Debug.logError(e,
0885: "Problem looking up OrderItemBilling records for : "
0886: + billFields, module);
0887: return ServiceUtil
0888: .returnError("Problem getting OrderItemBilling records");
0889: }
0890:
0891: // if none found, then okay to bill
0892: if (itemBillings == null || itemBillings.size() == 0) {
0893: itemsByOrder.add(itemIssuance);
0894: }
0895:
0896: // update the map with modified list
0897: shippedOrderItems.put(orderId, itemsByOrder);
0898: }
0899:
0900: // make sure we aren't billing items already invoiced i.e. items billed as digital (FINDIG)
0901: Set orders = shippedOrderItems.keySet();
0902: Iterator ordersIter = orders.iterator();
0903: while (ordersIter.hasNext()) {
0904: String orderId = (String) ordersIter.next();
0905:
0906: // we'll only use this list to figure out which ones to send
0907: List billItems = (List) shippedOrderItems.get(orderId);
0908:
0909: // a new list to be used to pass to the create invoice service
0910: List toBillItems = new ArrayList();
0911:
0912: // map of available quantities so we only have to calc once
0913: Map itemQtyAvail = new HashMap();
0914:
0915: // now we will check each issuance and make sure it hasn't already been billed
0916: Iterator billIt = billItems.iterator();
0917: while (billIt.hasNext()) {
0918: GenericValue issue = (GenericValue) billIt.next();
0919: Double issueQty = issue.getDouble("quantity");
0920: Double billAvail = (Double) itemQtyAvail.get(issue
0921: .getString("orderItemSeqId"));
0922: if (billAvail == null) {
0923: Map lookup = UtilMisc.toMap("orderId", orderId,
0924: "orderItemSeqId", issue
0925: .get("orderItemSeqId"));
0926: GenericValue orderItem = null;
0927: List billed = null;
0928: try {
0929: orderItem = issue.getRelatedOne("OrderItem");
0930: billed = delegator.findByAnd(
0931: "OrderItemBilling", lookup);
0932: } catch (GenericEntityException e) {
0933: Debug.logError(e,
0934: "Problem looking up OrderItem/OrderItemBilling records for : "
0935: + lookup, module);
0936: return ServiceUtil
0937: .returnError("Problem getting OrderItem/OrderItemBilling records");
0938: }
0939:
0940: // total ordered
0941: double orderedQty = orderItem.getDouble("quantity")
0942: .doubleValue();
0943:
0944: // add up the already billed total
0945: if (billed != null && billed.size() > 0) {
0946: double billedQuantity = 0.00;
0947: Iterator bi = billed.iterator();
0948: while (bi.hasNext()) {
0949: GenericValue oib = (GenericValue) bi.next();
0950: Double qty = oib.getDouble("quantity");
0951: if (qty != null) {
0952: billedQuantity += qty.doubleValue();
0953: }
0954: }
0955: double leftToBill = orderedQty - billedQuantity;
0956: billAvail = new Double(leftToBill);
0957: } else {
0958: billAvail = new Double(orderedQty);
0959: }
0960: }
0961:
0962: // no available means we cannot bill anymore
0963: if (billAvail != null && billAvail.doubleValue() > 0) {
0964: if (issueQty != null
0965: && issueQty.doubleValue() > billAvail
0966: .doubleValue()) {
0967: // can only bill some of the issuance; others have been billed already
0968: issue.set("quantity", billAvail);
0969: billAvail = new Double(0);
0970: } else {
0971: // now have been billed
0972: billAvail = new Double(billAvail.doubleValue()
0973: - issueQty.doubleValue());
0974: }
0975:
0976: // okay to bill these items; but none else
0977: toBillItems.add(issue);
0978: }
0979:
0980: // update the available to bill quantity for the next pass
0981: itemQtyAvail.put(issue.getString("orderItemSeqId"),
0982: billAvail);
0983: }
0984:
0985: // call the createInvoiceForOrder service for each order
0986: Map serviceContext = UtilMisc.toMap("orderId", orderId,
0987: "billItems", toBillItems, "userLogin", context
0988: .get("userLogin"));
0989: try {
0990: Map result = dispatcher.runSync(
0991: "createInvoiceForOrder", serviceContext);
0992: invoicesCreated.add(result.get("invoiceId"));
0993: } catch (GenericServiceException e) {
0994: Debug
0995: .logError(
0996: e,
0997: "Trouble calling createInvoiceForOrder service; invoice not created for shipment",
0998: module);
0999: return ServiceUtil
1000: .returnError("Trouble calling createInvoiceForOrder service; invoice not created for shipment");
1001: }
1002: }
1003:
1004: Map response = ServiceUtil.returnSuccess();
1005: response.put("invoicesCreated", invoicesCreated);
1006: return response;
1007: }
1008:
1009: private static String getInvoiceItemType(
1010: GenericDelegator delegator, String key, String defaultValue) {
1011: GenericValue itemMap = null;
1012: try {
1013: itemMap = delegator.findByPrimaryKey("InvoiceItemTypeMap",
1014: UtilMisc.toMap("invoiceItemMapKey", key));
1015: } catch (GenericEntityException e) {
1016: Debug
1017: .logError(
1018: e,
1019: "Trouble getting InvoiceItemTypeMap entity",
1020: module);
1021: return defaultValue;
1022: }
1023: if (itemMap != null) {
1024: return itemMap.getString("invoiceItemTypeId");
1025: } else {
1026: return defaultValue;
1027: }
1028: }
1029:
1030: public static Map checkInvoicePaymentApplications(
1031: DispatchContext ctx, Map context) {
1032: GenericDelegator delegator = ctx.getDelegator();
1033: LocalDispatcher dispatcher = ctx.getDispatcher();
1034: GenericValue userLogin = (GenericValue) context
1035: .get("userLogin");
1036: String invoiceId = (String) context.get("invoiceId");
1037: List paymentAppl = null;
1038: try {
1039: paymentAppl = delegator.findByAnd("PaymentApplication",
1040: UtilMisc.toMap("invoiceId", invoiceId));
1041: } catch (GenericEntityException e) {
1042: Debug.logError(e,
1043: "Problem getting PaymentApplication(s) for Invoice #"
1044: + invoiceId, module);
1045: return ServiceUtil
1046: .returnError("Problem getting PaymentApplication(s) for Invoice #"
1047: + invoiceId);
1048: }
1049:
1050: Map payments = new HashMap();
1051: if (paymentAppl != null) {
1052: Iterator pai = paymentAppl.iterator();
1053: while (pai.hasNext()) {
1054: GenericValue payAppl = (GenericValue) pai.next();
1055: payments.put(payAppl.getString("paymentId"), payAppl
1056: .getDouble("amountApplied"));
1057: }
1058: }
1059:
1060: double totalPayments = 0.00;
1061: Iterator pi = payments.keySet().iterator();
1062: while (pi.hasNext()) {
1063: String paymentId = (String) pi.next();
1064: Double amount = (Double) payments.get(paymentId);
1065: if (amount == null)
1066: amount = new Double(0.00);
1067: totalPayments += amount.doubleValue();
1068: }
1069:
1070: if (totalPayments > 0.00) {
1071: double invoiceTotal = InvoiceWorker.getInvoiceTotal(
1072: delegator, invoiceId);
1073: //Debug.log("Invoice #" + invoiceId + " total: " + invoiceTotal, module);
1074: //Debug.log("Total payments : " + totalPayments, module);
1075: if (totalPayments >= invoiceTotal) {
1076: // this invoice is paid
1077: Map svcCtx = UtilMisc.toMap("statusId", "INVOICE_PAID",
1078: "invoiceId", invoiceId, "userLogin", userLogin);
1079: try {
1080: Map stRes = dispatcher.runSync("setInvoiceStatus",
1081: svcCtx);
1082: } catch (GenericServiceException e) {
1083: Debug.logError(e,
1084: "Problem changing invoice status : "
1085: + svcCtx, module);
1086: return ServiceUtil
1087: .returnError("Problem changing invoice status");
1088: }
1089: }
1090: } else {
1091: Debug.log("No payments found for Invoice #" + invoiceId,
1092: module);
1093: }
1094:
1095: return ServiceUtil.returnSuccess();
1096: }
1097:
1098: private static double calcHeaderAdj(GenericDelegator delegator,
1099: GenericValue adj, String invoiceId, int itemSeqId,
1100: List toStore, double divisor, double multiplier,
1101: double invoiceQuantity) {
1102: //Debug.log("Divisor : " + divisor + " / Multiplier: " + multiplier, module);
1103: double adjAmount = 0.00;
1104: if (adj.get("amount") != null) {
1105: // pro-rate the amount
1106: double amount = ((adj.getDouble("amount").doubleValue() / divisor) * multiplier);
1107: if (amount != 0) {
1108: GenericValue invoiceItem = delegator.makeValue(
1109: "InvoiceItem", UtilMisc.toMap("invoiceId",
1110: invoiceId, "invoiceItemSeqId",
1111: new Integer(itemSeqId).toString()));
1112: invoiceItem.set("invoiceItemTypeId",
1113: getInvoiceItemType(delegator, adj
1114: .getString("orderAdjustmentTypeId"),
1115: "INVOICE_ADJ"));
1116: //invoiceItem.set("productId", orderItem.get("productId"));
1117: //invoiceItem.set("productFeatureId", orderItem.get("productFeatureId"));
1118: //invoiceItem.set("uomId", "");
1119: //invoiceItem.set("taxableFlag", product.get("taxable"));
1120: invoiceItem.set("quantity", new Double(1));
1121: invoiceItem.set("amount", new Double(amount));
1122: invoiceItem.set("description", adj.get("description"));
1123: toStore.add(invoiceItem);
1124: }
1125: adjAmount = amount;
1126: } else if (adj.get("percentage") != null
1127: || adj.get("amountPerQuantity") != null) {
1128: Double amountPerQty = adj.getDouble("amount");
1129: Double percent = adj.getDouble("percentage");
1130: double totalAmount = 0.00;
1131: if (percent != null)
1132: totalAmount += percent.doubleValue() * multiplier;
1133: if (amountPerQty != null)
1134: totalAmount += amountPerQty.doubleValue()
1135: * invoiceQuantity;
1136:
1137: if (totalAmount != 0) {
1138: GenericValue adjInvItem = delegator.makeValue(
1139: "InvoiceItem", UtilMisc.toMap("invoiceId",
1140: invoiceId, "invoiceItemSeqId",
1141: new Integer(itemSeqId).toString()));
1142: adjInvItem.set("invoiceItemTypeId", getInvoiceItemType(
1143: delegator, adj
1144: .getString("orderAdjustmentTypeId"),
1145: "INVOICE_ITM_ADJ"));
1146: //adjInvItem.set("productId", orderItem.get("productId"));
1147: //adjInvItem.set("productFeatureId", orderItem.get("productFeatureId"));
1148: //adjInvItem.set("uomId", "");
1149: //adjInvItem.set("taxableFlag", product.get("taxable"));
1150: adjInvItem.set("quantity", new Double(1));
1151: adjInvItem.set("amount", new Double(totalAmount));
1152: adjInvItem.set("description", adj.get("description"));
1153: toStore.add(adjInvItem);
1154: }
1155: adjAmount = totalAmount;
1156: }
1157:
1158: return adjAmount;
1159: }
1160: }
|