You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(4) |
Sep
|
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(22) |
Feb
(3) |
Mar
(1) |
Apr
|
May
(4) |
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Si C. <si...@op...> - 2007-07-10 23:06:58
|
Hello. I just wanted to let you know that this mailing list is deprecated. All new commits for opentaps developments are now sent to the opentaps-crmcommits mailing list: http://lists.sourceforge.net/mailman/listinfo/opentaps-crmcommits Please subscribe to that list if you'd like to keep up to date on our work. Thanks! Si |
From: Si C. <si...@gr...> - 2007-05-10 16:16:08
|
Author: sichen Date: 2007-05-10 09:16:05 -0700 (Thu, 10 May 2007) New Revision: 64 Modified: versions/0.9/trunk/README.txt Log: Fix typos Modified: versions/0.9/trunk/README.txt =================================================================== --- versions/0.9/trunk/README.txt 2007-05-09 22:29:40 UTC (rev 63) +++ versions/0.9/trunk/README.txt 2007-05-10 16:16:05 UTC (rev 64) @@ -7,7 +7,8 @@ To use it, put this entire module and all its sub-directories in the hot-deploy/ directory of your opentaps/OFBiz suite. - If you are using this module with the current SVN version of OFBIZ, you + This version is designed to work with opentaps 0.9. You should use the 1.0 version for opentaps 1.0. +If you are using this module with another SVN version of OFBIZ, you will need to mdoify the build file build.xml to use the new directory structure in the OFBIZ framework. You can either use patch to change the build.xml by doing a: @@ -19,12 +20,12 @@ If you have problems with $ ant -then edit the financials/build.xml file and change the line for +then edit the dataimport/build.xml file and change the line for <property name="ofbiz.dir" value="../../"/> to the absolute path of your ofbiz/ directory. If you are using Eclipse, edit the .classpath file in your ofbiz/ directory and add the line - <classpathentry kind="src" path="hot-deploy/financials/src"/> + <classpathentry kind="src" path="hot-deploy/dataimport/src"/> so Eclipse would load the src/ directory as Java files. Licensing @@ -38,7 +39,7 @@ as a service. The HPL allows you to use, modify, and re-distribute it, provided you meet its requirements. The HPL is a very different license than the MIT/Apache License of OFBiz. Please take the time to -understand its differences and observe them in your use of both the Financials module and of larger +understand its differences and observe them in your use of both the dataimport module and of larger applications with which you have combined it. If you do not wish to be bound by the HPL in your use of this application, we also offer |
From: Leon T. <le...@gr...> - 2007-05-09 22:30:01
|
Author: leon Date: 2007-05-09 15:29:40 -0700 (Wed, 09 May 2007) New Revision: 63 Added: versions/0.9/tags/dataimport-1.0/ Log: Creating tag where we created the 1.0 branch from Copied: versions/0.9/tags/dataimport-1.0 (from rev 62, versions/0.9/trunk) |
From: Si C. <si...@gr...> - 2007-05-02 20:54:28
|
Author: sichen Date: 2007-05-02 13:54:06 -0700 (Wed, 02 May 2007) New Revision: 62 Modified: versions/0.9/trunk/entitydef/entitymodel_order.xml Log: isclosed duplicates orderclosed Modified: versions/0.9/trunk/entitydef/entitymodel_order.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-05-02 20:50:54 UTC (rev 61) +++ versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-05-02 20:54:06 UTC (rev 62) @@ -44,9 +44,8 @@ <field name="taxTotal" type="currency-amount"></field> <field name="adjustmentsTotal" type="currency-amount"></field> <field name="grandTotal" type="currency-amount"></field> - <field name="isClosed" type="indicator"><description>If set to N or n, the order will be created in the Approved state.</description></field> <field name="comments" type="comment"></field> - <field name="orderClosed" type="indicator"></field> + <field name="orderClosed" type="indicator"><description>If set to N or n, the order will be created in the Approved state.</description></field> <field name="processedTimestamp" type="date-time"> <description>Special field for system to record when entry was successfully imported. Do not use for any other purpose.</description> |
From: Si C. <si...@gr...> - 2007-05-02 20:50:58
|
Author: sichen Date: 2007-05-02 13:50:54 -0700 (Wed, 02 May 2007) New Revision: 61 Modified: versions/0.9/trunk/entitydef/entitymodel_order.xml versions/0.9/trunk/entitydef/entitymodel_product.xml Log: Added new fields to manage inactive products and not-closed orders Modified: versions/0.9/trunk/entitydef/entitymodel_order.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-03-05 17:42:14 UTC (rev 60) +++ versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-05-02 20:50:54 UTC (rev 61) @@ -44,6 +44,7 @@ <field name="taxTotal" type="currency-amount"></field> <field name="adjustmentsTotal" type="currency-amount"></field> <field name="grandTotal" type="currency-amount"></field> + <field name="isClosed" type="indicator"><description>If set to N or n, the order will be created in the Approved state.</description></field> <field name="comments" type="comment"></field> <field name="orderClosed" type="indicator"></field> <field name="processedTimestamp" type="date-time"> @@ -68,6 +69,7 @@ <field name="orderId" type="id-ne"></field> <field name="productId" type="id"></field> <field name="quantity" type="floating-point"></field> + <field name="quantityShipped" type="floating-point"><description>Quantity of this order item already shipped, meaningful only for not closed orders.</description></field> <field name="price" type="currency-amount"></field> <field name="itemAdjustmentsTotal" type="currency-amount"></field> <field name="customerPo" type="id"></field> Modified: versions/0.9/trunk/entitydef/entitymodel_product.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_product.xml 2007-03-05 17:42:14 UTC (rev 60) +++ versions/0.9/trunk/entitydef/entitymodel_product.xml 2007-05-02 20:50:54 UTC (rev 61) @@ -37,6 +37,7 @@ title="Intermediate import entity for product data."> <field name="productId" type="id-ne"/> <field name="productTypeId" type="id-ne"/> + <field name="isInactive" type="indicator"><description>If set to Y or y, the product is set to discontinued at time of import</description></field> <field name="customId1" type="id"/> <field name="customId2" type="id"/> <field name="description" type="description"/> |
From: Si C. <si...@gr...> - 2007-03-05 17:42:35
|
Author: sichen Date: 2007-03-05 09:42:14 -0800 (Mon, 05 Mar 2007) New Revision: 60 Modified: versions/0.9/trunk/script/mysql/importBOMExample.sql Log: Added note about initiailizing BOM low level code after importing BOMs Modified: versions/0.9/trunk/script/mysql/importBOMExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importBOMExample.sql 2007-02-19 18:43:41 UTC (rev 59) +++ versions/0.9/trunk/script/mysql/importBOMExample.sql 2007-03-05 17:42:14 UTC (rev 60) @@ -1,5 +1,6 @@ --This is a simple example of importing a Bill of Materials. The products must have already been imported with product imports --and the BOM file basically has productId, productIdTo, and quantity. I +--NOTE: after you import a BOM this way, you must run the service "initLowLevelCode" to set the Product.billOfMaterialsLevel. load data local infile '' |
From: Si C. <si...@gr...> - 2007-02-19 18:43:46
|
Author: sichen Date: 2007-02-19 10:43:41 -0800 (Mon, 19 Feb 2007) New Revision: 59 Added: versions/0.9/tags/release-0.9.4/ Log: 0.9.4 release version Copied: versions/0.9/tags/release-0.9.4 (from rev 58, versions/0.9/trunk) |
From: Si C. <si...@gr...> - 2007-02-13 19:47:24
|
Author: sichen Date: 2007-02-13 11:47:15 -0800 (Tue, 13 Feb 2007) New Revision: 58 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Log: fix an incompatibility with java 1.4 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-02-09 04:57:19 UTC (rev 57) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-02-13 19:47:15 UTC (rev 58) @@ -361,7 +361,7 @@ BigDecimal averageCost = ZERO; if (onHand.doubleValue() > 0.0) { - averageCost = new BigDecimal(inventoryValue/onHand).setScale(decimals, rounding); + averageCost = new BigDecimal(inventoryValue.doubleValue()/onHand.doubleValue()).setScale(decimals, rounding); } // Verify that productId exists |
From: <cli...@gr...> - 2007-02-09 04:57:21
|
Author: cliberty Date: 2007-02-08 20:57:19 -0800 (Thu, 08 Feb 2007) New Revision: 57 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java Log: Fix for 1655665: Reverting autoboxing usage to make OrderImportServices compile under JDK1.4 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-01-31 16:05:25 UTC (rev 56) +++ versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-02-09 04:57:19 UTC (rev 57) @@ -172,7 +172,7 @@ orderHeaderInput.put("salesChannelEnumId", "UNKNWN_SALES_CHANNEL"); orderHeaderInput.put("orderDate", orderDate); orderHeaderInput.put("entryDate", UtilDateTime.nowTimestamp()); - orderHeaderInput.put("statusId", externalOrderHeader.getBoolean("orderClosed") ? "ORDER_COMPLETED" : "ORDER_APPROVED"); + orderHeaderInput.put("statusId", externalOrderHeader.getBoolean("orderClosed").booleanValue() ? "ORDER_COMPLETED" : "ORDER_APPROVED"); orderHeaderInput.put("currencyUom", externalOrderHeader.get("currencyUomId")); orderHeaderInput.put("productStoreId", productStoreId); orderHeaderInput.put("remainingSubTotal", new Double(0)); |
From: <cli...@gr...> - 2007-01-31 16:05:44
|
Author: cliberty Date: 2007-01-31 08:05:25 -0800 (Wed, 31 Jan 2007) New Revision: 56 Modified: versions/0.9/trunk/entitydef/entitymodel_order.xml versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java Log: Adding an orderClosed (indicator) column to the DataImportOrderHeader entity, and logic to the MySQL example script and importOrders service to handle it. If DataImportOrderHeader.orderClosed=='Y', OrderHeader.statusId will be ORDER_COMPLETED, otherwise it will be ORDER_APPROVED. Modified: versions/0.9/trunk/entitydef/entitymodel_order.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-01-30 02:28:57 UTC (rev 55) +++ versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-01-31 16:05:25 UTC (rev 56) @@ -45,6 +45,7 @@ <field name="adjustmentsTotal" type="currency-amount"></field> <field name="grandTotal" type="currency-amount"></field> <field name="comments" type="comment"></field> + <field name="orderClosed" type="indicator"></field> <field name="processedTimestamp" type="date-time"> <description>Special field for system to record when entry was successfully imported. Do not use for any other purpose.</description> Modified: versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql 2007-01-30 02:28:57 UTC (rev 55) +++ versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql 2007-01-31 16:05:25 UTC (rev 56) @@ -4,6 +4,7 @@ -- grandTotal, shippingTotal, taxTotal, adjustmentsTotal may be positive or negative numbers -- currencyUomId must exist in the Uom entity -- orderTypeId must exist in the OrderType entity +-- orderClosed must be Y or N load data local infile '' @@ -17,12 +18,14 @@ @orderId, @orderDate, @customerId, + @ignore, @grandTotal, @shippingTotal, @taxTotal, @adjustmentsTotal, @currencyUomId, @comments, + @orderClosed, @orderTypeId, ) @@ -36,5 +39,6 @@ tax_total = nullif(trim(@taxTotal),''), adjustments_total = nullif(trim(@adjustmentsTotal),''), grand_total = nullif(trim(@grandTotal),''), +order_closed = nullif(trim(@orderClosed),''), comments = nullif(trim(@comments),''); Modified: versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-01-30 02:28:57 UTC (rev 55) +++ versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-01-31 16:05:25 UTC (rev 56) @@ -172,7 +172,7 @@ orderHeaderInput.put("salesChannelEnumId", "UNKNWN_SALES_CHANNEL"); orderHeaderInput.put("orderDate", orderDate); orderHeaderInput.put("entryDate", UtilDateTime.nowTimestamp()); - orderHeaderInput.put("statusId", "ORDER_COMPLETED"); + orderHeaderInput.put("statusId", externalOrderHeader.getBoolean("orderClosed") ? "ORDER_COMPLETED" : "ORDER_APPROVED"); orderHeaderInput.put("currencyUom", externalOrderHeader.get("currencyUomId")); orderHeaderInput.put("productStoreId", productStoreId); orderHeaderInput.put("remainingSubTotal", new Double(0)); |
From: <cli...@gr...> - 2007-01-30 02:29:00
|
Author: cliberty Date: 2007-01-29 18:28:57 -0800 (Mon, 29 Jan 2007) New Revision: 55 Added: versions/0.9/trunk/script/mysql/importProductInventoryExample.sql Modified: versions/0.9/trunk/entitydef/entitygroup.xml versions/0.9/trunk/entitydef/entitymodel_product.xml versions/0.9/trunk/servicedef/services.xml versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Log: 1645751: Move inventory import to dataimport Modified: versions/0.9/trunk/entitydef/entitygroup.xml =================================================================== --- versions/0.9/trunk/entitydef/entitygroup.xml 2007-01-29 18:45:39 UTC (rev 54) +++ versions/0.9/trunk/entitydef/entitygroup.xml 2007-01-30 02:28:57 UTC (rev 55) @@ -30,6 +30,7 @@ <!-- =================================== --> <entity-group group="org.ofbiz" entity="DataImportProduct"/> + <entity-group group="org.ofbiz" entity="DataImportInventory"/> <!-- =================================== --> <!-- org.opentaps.dataimport.orders --> Modified: versions/0.9/trunk/entitydef/entitymodel_product.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_product.xml 2007-01-29 18:45:39 UTC (rev 54) +++ versions/0.9/trunk/entitydef/entitymodel_product.xml 2007-01-30 02:28:57 UTC (rev 55) @@ -27,7 +27,7 @@ <version>1.0</version> <!-- ================================= --> - <!-- org.opentaps.dataimport.customers --> + <!-- org.opentaps.dataimport.products --> <!-- ================================= --> <!-- for precise definitions of the field types see the file framework/entity/fieldtype/fieldtypeXXX.xml for your database XXX --> @@ -58,4 +58,19 @@ <prim-key field="productId"/> </entity> + <entity entity-name="DataImportInventory" + package-name="org.opentaps.dataimport.products" + title="Intermediate import entity for inventory data."> + <field name="productId" type="id"/> + <!--<field name="productName" type="description"/>--> + <field name="availableToPromise" type="floating-point"/> + <field name="onHand" type="floating-point"/> + <field name="inventoryValue" type="currency-amount"/> + <field name="processedTimestamp" type="date-time"/> + <prim-key field="productId"/> + <relation type="one" fk-name="IMPT_INV_PROD" rel-entity-name="Product"> + <key-map field-name="productId"/> + </relation> + </entity> + </entitymodel> Added: versions/0.9/trunk/script/mysql/importProductInventoryExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importProductInventoryExample.sql 2007-01-29 18:45:39 UTC (rev 54) +++ versions/0.9/trunk/script/mysql/importProductInventoryExample.sql 2007-01-30 02:28:57 UTC (rev 55) @@ -0,0 +1,25 @@ +-- Example MySQL script for importing product inventory +-- productId must exist in the Product entity +-- availableToPromise, onHand, and inventoryValue may be positive or negative numbers + + +load data local infile +'' +ignore +into table data_import_inventory +fields optionally enclosed by '"' +lines terminated by '\r' +ignore 1 lines + +( + @productId, + @availableToPromise, + @onHand, + @inventoryValue +) + +set +product_id = nullif(trim(@productId),''), +available_to_promise = nullif(trim(@availableToPromise),''), +on_hand = nullif(trim(@onHand),''), +inventory_value = nullif(trim(@inventoryValue),'') Property changes on: versions/0.9/trunk/script/mysql/importProductInventoryExample.sql ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Date Rev Author URL Id Name: svn:eol-style + native Modified: versions/0.9/trunk/servicedef/services.xml =================================================================== --- versions/0.9/trunk/servicedef/services.xml 2007-01-29 18:45:39 UTC (rev 54) +++ versions/0.9/trunk/servicedef/services.xml 2007-01-30 02:28:57 UTC (rev 55) @@ -76,4 +76,18 @@ <attribute type="Integer" mode="OUT" name="productsImported" optional="true"/> </service> + <service name="importProductInventory" engine="java" use-transaction="false" + location="org.opentaps.dataimport.ProductImportServices" invoke="importProductInventory"> + <description> + Import product inventory using DataImportInventory. + Note that this service is not wrapped in a transaction. Each inventory record set imported is in its + own transaction, so it can store as many good records as possible. + </description> + <attribute name="organizationPartyId" type="String" mode="IN" optional="false"/> + <attribute name="facilityId" type="String" mode="IN" optional="false"/> + <attribute name="inventoryGlAccountId" type="String" mode="IN" optional="false"/> + <attribute name="offsettingGlAccountId" type="String" mode="IN" optional="false"/> + <attribute name="importedRecords" type="Integer" mode="OUT" optional="true"/> + </service> + </services> Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-29 18:45:39 UTC (rev 54) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-30 02:28:57 UTC (rev 55) @@ -31,6 +31,8 @@ import org.ofbiz.entity.transaction.TransactionUtil; import org.ofbiz.service.ServiceUtil; import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.LocalDispatcher; +import org.ofbiz.service.GenericServiceException; /** * Import products via intermediate DataImportProduct entity. @@ -38,8 +40,12 @@ * @author <a href="mailto:le...@op...">Leon Torres</a> */ public class ProductImportServices { - + public static String module = ProductImportServices.class.getName(); + public static final int decimals = UtilNumber.getBigDecimalScale("order.decimals"); + public static final int rounding = UtilNumber.getBigDecimalRoundingMode("order.rounding"); + public static final BigDecimal ZERO = (new BigDecimal("0")).setScale(decimals, rounding); + private static int acctgTransSeqNum = 1; public static Map importProducts(DispatchContext dctx, Map context) { GenericDelegator delegator = dctx.getDelegator(); @@ -123,6 +129,131 @@ return results; } + public static Map importProductInventory(DispatchContext dctx, Map context) { + GenericDelegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String organizationPartyId = (String) context.get("organizationPartyId"); + String facilityId = (String) context.get("facilityId"); + String inventoryGlAccountId = (String) context.get("inventoryGlAccountId"); + String offsettingGlAccountId = (String) context.get("offsettingGlAccountId"); + Timestamp now = UtilDateTime.nowTimestamp(); + + int imported = 0; + + // main try/catch block that traps errors related to obtaining data from delegator + try { + + // Make sure the organizationParty exists + GenericValue organizationParty = delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", organizationPartyId)); + + if (UtilValidate.isEmpty(organizationParty)) { + String errMsg = "Error in importProductInventory service: party [" + organizationPartyId + "] does not exist"; + Debug.logError(errMsg, module); + return ServiceUtil.returnError(errMsg); + } + + // Make sure the facility exists + if (! UtilValidate.isEmpty(facilityId)) { + GenericValue facility = delegator.findByPrimaryKey("Facility", UtilMisc.toMap("facilityId", facilityId)); + + if (UtilValidate.isEmpty(facility)) { + String errMsg = "Error in importProductInventory service: facility [" + facilityId + "] does not exist"; + Debug.logError(errMsg, module); + return ServiceUtil.returnError(errMsg); + } + } + + // Make sure the supplied GL accounts exist for the organization + GenericValue glAccountOrganization = null; + if (! UtilValidate.isEmpty(inventoryGlAccountId)) { + glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", inventoryGlAccountId, "organizationPartyId", organizationPartyId)); + if (glAccountOrganization == null) { + return ServiceUtil.returnError("Cannot import inventory: organization ["+organizationPartyId+"] does not have inventory General Ledger account ["+inventoryGlAccountId+"] defined in GlAccountOrganization."); + } + } + if (! UtilValidate.isEmpty(offsettingGlAccountId)) { + glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", offsettingGlAccountId, "organizationPartyId", organizationPartyId)); + if (glAccountOrganization == null) { + return ServiceUtil.returnError("Cannot import inventory: organization ["+organizationPartyId+"] does not have offsetting General Ledger account ["+offsettingGlAccountId+"] defined in GlAccountOrganization."); + } + } + + // Get the base currency for the organization + GenericValue partyAcctgPref = delegator.findByPrimaryKeyCache("PartyAcctgPreference", UtilMisc.toMap("partyId", organizationPartyId)); + if (UtilValidate.isEmpty(partyAcctgPref)) { + String errMsg = "Error in importProductInventory service: organization [" + organizationPartyId + "] does not have a PartyAcctgPref record"; + Debug.logError(errMsg, module); + return ServiceUtil.returnError(errMsg); + } + String currencyUomId = partyAcctgPref.getString("baseCurrencyUomId"); + if (UtilValidate.isEmpty(currencyUomId)) { + String errMsg = "Error in importProductInventory service: organization [" + organizationPartyId + "] does not have a baseCurrencyUomId defined in PartyAcctgPref"; + Debug.logError(errMsg, module); + return ServiceUtil.returnError(errMsg); + } + + // Create the header of an AcctgTrans record for all the subsequent transaction entries + Map createAcctgTransResults = dispatcher.runSync("createAcctgTrans", UtilMisc.toMap("acctgTransTypeId", "INTERNAL_ACCTG_TRANS", "glFiscalTypeId", "ACTUAL", "transactionDate", now, "userLogin", userLogin)); + if (ServiceUtil.isError(createAcctgTransResults)) { + return createAcctgTransResults; + } + String acctgTransId = (String) createAcctgTransResults.get("acctgTransId"); + + // need to get an ELI because of possibly large number of records. productId <> null will get all records + EntityConditionList conditions = new EntityConditionList( UtilMisc.toList( + new EntityExpr("productId", EntityOperator.NOT_EQUAL, null), + new EntityExpr("processedTimestamp", EntityOperator.EQUALS, null) // leave out previously processed orders + ), EntityOperator.AND); + TransactionUtil.begin(); + EntityListIterator importProductInventory = delegator.findListIteratorByCondition("DataImportInventory", conditions, null, null); + TransactionUtil.commit(); + + GenericValue productInventory = null; + while ((productInventory = (GenericValue) importProductInventory.next()) != null) { + + try { + + List toStore = decodeInventory(productInventory, organizationPartyId, facilityId, inventoryGlAccountId, offsettingGlAccountId, acctgTransId, currencyUomId, now, delegator); + if (toStore == null) { + Debug.logWarning("Import of product inventory["+productInventory.get("productId")+"] was unsuccessful.", module); + } + + TransactionUtil.begin(); + + delegator.storeAll(toStore); + + Debug.logInfo("Successfully imported product inventory ["+productInventory.get("productId")+"].", module); + imported++; + + TransactionUtil.commit(); + + } catch ( GenericEntityException e) { + TransactionUtil.rollback(); + Debug.logError(e, "Failed to import product inventory["+productInventory.get("productId")+"]. Error stack follows.", module); + } catch (Exception e) { + TransactionUtil.rollback(); + Debug.logWarning("Import of product inventory["+productInventory.get("productId")+"] was unsuccessful.", module); + } + } + importProductInventory.close(); + + } catch ( GenericServiceException se) { + String errMsg = "Error in importProductInventory service: " + se.getMessage(); + Debug.logError(se, errMsg, module); + return ServiceUtil.returnError(errMsg); + } catch (GenericEntityException ee) { + String errMsg = "Error in importProductInventory service: " + ee.getMessage(); + Debug.logError(ee, errMsg, module); + return ServiceUtil.returnError(errMsg); + } + + Map results = ServiceUtil.returnSuccess(); + results.put("importedRecords", new Integer(imported)); + return results; + } + /** * Helper method to decode a DataImportProduct into a List of GenericValues modeling that product in the OFBiz schema. * If for some reason obtaining data via the delegator fails, this service throws that exception. @@ -205,11 +336,106 @@ GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl", input); toStore.add(productFeatureAppl); } - + // update the original data record with a timestamp which also denotes that it has been processed (processedTimestamp = null was original search condition) data.set("processedTimestamp", UtilDateTime.nowTimestamp()); toStore.add(data); return toStore; } + + /** + * Helper method to decode a DataImportInventory into a List of GenericValues modeling that product in the OFBiz schema. + * If for some reason obtaining data via the delegator fails, this service throws that exception. + * Note that everything is done with the delegator for maximum efficiency. + */ + private static List decodeInventory(GenericValue productInventory, String organizationPartyId, String facilityId, String inventoryGlAccountId, String offsettingGlAccountId, String acctgTransId, String currencyUomId, Timestamp now, GenericDelegator delegator) throws GenericEntityException, Exception { + Map input; + List toStore = FastList.newInstance(); + Debug.logInfo("Now processing data [" + productInventory.get("productId") + "]", module); + + String productId = productInventory.getString("productId"); + Double onHand = productInventory.getDouble("onHand"); + Double availableToPromise = productInventory.getDouble("availableToPromise"); + Double inventoryValue = productInventory.getDouble("inventoryValue"); + + BigDecimal averageCost = ZERO; + if (onHand.doubleValue() > 0.0) { + averageCost = new BigDecimal(inventoryValue/onHand).setScale(decimals, rounding); + } + + // Verify that productId exists + GenericValue product = delegator.findByPrimaryKey("Product", UtilMisc.toMap("productId", productId)); + if (product == null) { + Debug.logInfo("Could not find product ["+productId+"], not importing.", module); + return toStore; + } + + String inventoryItemId = delegator.getNextSeqId("InventoryItem"); + + // Create the inventory item + input = FastMap.newInstance(); + input.put("inventoryItemId", inventoryItemId); + input.put("unitCost", new Double(averageCost.doubleValue())); + input.put("productId", productId); + input.put("ownerPartyId", organizationPartyId); + input.put("datetimeReceived", now); + input.put("facilityId", facilityId); + input.put("comments", "Auto-generated from Product Inventory Import."); + input.put("inventoryItemTypeId", "NON_SERIAL_INV_ITEM"); + input.put("currencyUomId", currencyUomId); + GenericValue inventoryItem = delegator.makeValue("InventoryItem", input); + toStore.add(inventoryItem); + + // Create the inventory item detail + input = FastMap.newInstance(); + input.put("inventoryItemId", inventoryItemId); + input.put("inventoryItemDetailSeqId", UtilFormatOut.formatPaddedNumber(1, 4)); + input.put("quantityOnHandDiff", onHand); + if (! UtilValidate.isEmpty(availableToPromise)) { + input.put("availableToPromiseDiff", availableToPromise); + } else { + input.put("availableToPromiseDiff", onHand); + } + GenericValue inventoryItemDetail = delegator.makeValue("InventoryItemDetail", input); + toStore.add(inventoryItemDetail); + + // Create the product average cost + input = FastMap.newInstance(); + input.put("organizationPartyId", organizationPartyId); + input.put("fromDate", now); + input.put("averageCost", new Double(averageCost.doubleValue())); + input.put("productId", productId); + GenericValue productAverageCost = delegator.makeValue("ProductAverageCost", input); + toStore.add(productAverageCost); + + // Create the two AcctgTransEntries for this item + input = FastMap.newInstance(); + input.put("acctgTransId", acctgTransId); + input.put("acctgTransEntrySeqId", UtilFormatOut.formatPaddedNumber(acctgTransSeqNum, 5)); + input.put("acctgTransEntryTypeId", "_NA_"); + input.put("productId", productId); + input.put("organizationPartyId", organizationPartyId); + input.put("currencyUomId", currencyUomId); + input.put("reconcileStatusId", "AES_NOT_RECONCILED"); + input.put("glAccountId", inventoryGlAccountId); + input.put("debitCreditFlag", "D"); + input.put("amount", inventoryValue); + GenericValue debitAcctgTransEntry = delegator.makeValue("AcctgTransEntry", input); + toStore.add(debitAcctgTransEntry); + acctgTransSeqNum++; + + input.put("acctgTransEntrySeqId", UtilFormatOut.formatPaddedNumber(acctgTransSeqNum, 5)); + input.put("glAccountId", offsettingGlAccountId); + input.put("debitCreditFlag", "C"); + GenericValue creditAcctgTransEntry = delegator.makeValue("AcctgTransEntry", input); + toStore.add(creditAcctgTransEntry); + acctgTransSeqNum++; + + // Update the original productInventory record with a timestamp which also denotes that it has been processed (processedTimestamp = null was original search condition) + productInventory.set("processedTimestamp", UtilDateTime.nowTimestamp()); + toStore.add(productInventory); + + return toStore; + } } |
From: <cli...@gr...> - 2007-01-29 18:45:50
|
Author: cliberty Date: 2007-01-29 10:45:39 -0800 (Mon, 29 Jan 2007) New Revision: 54 Modified: versions/0.9/trunk/servicedef/services.xml versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Log: Making goodIdentificationTypeId1 and 2 optional parameters in the importProducts service. Modified: versions/0.9/trunk/servicedef/services.xml =================================================================== --- versions/0.9/trunk/servicedef/services.xml 2007-01-24 17:30:04 UTC (rev 53) +++ versions/0.9/trunk/servicedef/services.xml 2007-01-29 18:45:39 UTC (rev 54) @@ -46,8 +46,8 @@ own transaction, so it can store as many good records as possible. The goodIdentificationTypeIdN parameters correspond to the type of the customIdN fields in DataImportProduct. </description> - <attribute type="String" mode="IN" name="goodIdentificationTypeId1" optional="false"/> - <attribute type="String" mode="IN" name="goodIdentificationTypeId2" optional="false"/> + <attribute type="String" mode="IN" name="goodIdentificationTypeId1" optional="true"/> + <attribute type="String" mode="IN" name="goodIdentificationTypeId2" optional="true"/> <attribute type="Integer" mode="OUT" name="productsImported" optional="true"/> </service> Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-24 17:30:04 UTC (rev 53) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-29 18:45:39 UTC (rev 54) @@ -53,6 +53,23 @@ // main try/catch block that traps errors related to obtaining data from delegator try { + + // make sure the supplied goodIdentificationTypes exist + GenericValue goodIdentificationType1 = null; + if (! UtilValidate.isEmpty(goodIdentificationTypeId1)) { + goodIdentificationType1 = delegator.findByPrimaryKey("GoodIdentificationType", UtilMisc.toMap("goodIdentificationTypeId", goodIdentificationTypeId1)); + if (goodIdentificationType1 == null) { + return ServiceUtil.returnError("Cannot import products: goodIdentificationType ["+goodIdentificationTypeId1+"] does not exist."); + } + } + GenericValue goodIdentificationType2 = null; + if (! UtilValidate.isEmpty(goodIdentificationTypeId2)) { + goodIdentificationType2 = delegator.findByPrimaryKey("GoodIdentificationType", UtilMisc.toMap("goodIdentificationTypeId", goodIdentificationTypeId1)); + if (goodIdentificationType2 == null) { + return ServiceUtil.returnError("Cannot import products: goodIdentificationType ["+goodIdentificationTypeId2+"] does not exist."); + } + } + // need to get an ELI because of possibly large number of records. productId <> null will get all records EntityConditionList conditions = new EntityConditionList( UtilMisc.toList( new EntityExpr("productId", EntityOperator.NOT_EQUAL, null), @@ -151,7 +168,7 @@ toStore.add(productPrice); // good identification (this is per customIdN) - if (!UtilValidate.isEmpty(data.getString("customId1"))) { + if (!UtilValidate.isEmpty(data.getString("customId1")) && !UtilValidate.isEmpty(goodIdentificationTypeId1)) { input = FastMap.newInstance(); input.put("goodIdentificationTypeId", goodIdentificationTypeId1); input.put("productId", product.get("productId")); @@ -159,7 +176,7 @@ GenericValue goodIdentification = delegator.makeValue("GoodIdentification", input); toStore.add(goodIdentification); } - if (!UtilValidate.isEmpty(data.getString("customId2"))) { + if (!UtilValidate.isEmpty(data.getString("customId1")) && !UtilValidate.isEmpty(goodIdentificationTypeId2)) { input = FastMap.newInstance(); input.put("goodIdentificationTypeId", goodIdentificationTypeId2); input.put("productId", product.get("productId")); |
From: <cli...@gr...> - 2007-01-24 17:30:13
|
Author: cliberty Date: 2007-01-24 09:30:04 -0800 (Wed, 24 Jan 2007) New Revision: 53 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Log: Populating Product.isVirtual and .isVariant during product import (assumes N for both) Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-24 16:34:50 UTC (rev 52) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-24 17:30:04 UTC (rev 53) @@ -131,6 +131,8 @@ input.put("widthUomId", data.get("widthUomId")); input.put("weight", data.get("weight")); input.put("weightUomId", data.get("weightUomId")); + input.put("isVirtual", "N"); + input.put("isVariant", "N"); input.put("createdDate", now); GenericValue product = delegator.makeValue("Product", input); toStore.add(product); |
From: <cli...@gr...> - 2007-01-24 16:34:54
|
Author: cliberty Date: 2007-01-24 08:34:50 -0800 (Wed, 24 Jan 2007) New Revision: 52 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java Log: Expanded on a todo Modified: versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-01-24 16:32:36 UTC (rev 51) +++ versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-01-24 16:34:50 UTC (rev 52) @@ -182,7 +182,7 @@ // todo:Make orderAdjustments from adjustmentsTotal and taxTotal if (! ignoreShippingHeaderAdjustment) { - // todo:Make orderAdjustments from shippingTotal + // todo:Make orderAdjustment from shippingTotal (only if ignoreShippingHeaderAdjustment is false) } // OrderItems |
From: <cli...@gr...> - 2007-01-24 16:32:42
|
Author: cliberty Date: 2007-01-24 08:32:36 -0800 (Wed, 24 Jan 2007) New Revision: 51 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java Log: Adding company name to name of imported PriceRules for easier reference Modified: versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java 2007-01-24 15:03:35 UTC (rev 50) +++ versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java 2007-01-24 16:32:36 UTC (rev 51) @@ -434,7 +434,9 @@ if (companyPartyId != null) { // productPriceRule String productPriceRuleId = delegator.getNextSeqId("ProductPriceRule"); - toStore.add(delegator.makeValue("ProductPriceRule", UtilMisc.toMap("productPriceRuleId", productPriceRuleId, "ruleName", "Imported rule for partyId " + companyPartyId, "isSale", "N", "fromDate", now))); + String priceRuleName = "Imported rule for "; + priceRuleName += UtilValidate.isEmpty(customer.get("companyName")) ? "partyId: " + companyPartyId : customer.getString("companyName"); + toStore.add(delegator.makeValue("ProductPriceRule", UtilMisc.toMap("productPriceRuleId", productPriceRuleId, "ruleName", priceRuleName, "isSale", "N", "fromDate", now))); // productPriceCond toStore.add(delegator.makeValue("ProductPriceCond", UtilMisc.toMap("productPriceRuleId", productPriceRuleId, "productPriceCondSeqId", UtilFormatOut.formatPaddedNumber(1, 2), "inputParamEnumId", "PRIP_PARTY_ID", "operatorEnumId", "PRC_EQ", "condValue", companyPartyId))); // productPriceAction |
From: <cli...@gr...> - 2007-01-24 15:03:53
|
Author: cliberty Date: 2007-01-24 07:03:35 -0800 (Wed, 24 Jan 2007) New Revision: 50 Modified: versions/0.9/trunk/servicedef/services.xml versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java Log: Making glAccountId parameters optional for the importCustomers service Modified: versions/0.9/trunk/servicedef/services.xml =================================================================== --- versions/0.9/trunk/servicedef/services.xml 2007-01-22 17:54:22 UTC (rev 49) +++ versions/0.9/trunk/servicedef/services.xml 2007-01-24 15:03:35 UTC (rev 50) @@ -32,8 +32,8 @@ own transaction, so it can store as many good records as possible. </description> <attribute type="String" mode="IN" name="initialResponsiblePartyId" optional="false"/> - <attribute type="String" mode="IN" name="arGlAccountId" optional="false"/> - <attribute type="String" mode="IN" name="offsettingGlAccountId" optional="false"/> + <attribute type="String" mode="IN" name="arGlAccountId" optional="true"/> + <attribute type="String" mode="IN" name="offsettingGlAccountId" optional="true"/> <attribute type="String" mode="IN" name="organizationPartyId" optional="false"/> <attribute type="Integer" mode="OUT" name="customersImported" optional="true"/> </service> Modified: versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java 2007-01-22 17:54:22 UTC (rev 49) +++ versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java 2007-01-24 15:03:35 UTC (rev 50) @@ -148,16 +148,20 @@ } // make sure the supplied GL accounts exist for the organization - GenericValue glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", arGlAccountId, "organizationPartyId", organizationPartyId)); - if (glAccountOrganization == null) { -// return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have Accounts Receivable General Ledger account ["+arGlAccountId+"] defined in GlAccountOrganization."); + GenericValue glAccountOrganization = null; + if (! UtilValidate.isEmpty(arGlAccountId)) { + glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", arGlAccountId, "organizationPartyId", organizationPartyId)); + if (glAccountOrganization == null) { + return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have Accounts Receivable General Ledger account ["+arGlAccountId+"] defined in GlAccountOrganization."); + } } - glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", offsettingGlAccountId, "organizationPartyId", organizationPartyId)); - if (glAccountOrganization == null) { -// return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have offsetting General Ledger account ["+offsettingGlAccountId+"] defined in GlAccountOrganization."); + if (! UtilValidate.isEmpty(offsettingGlAccountId)) { + glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", offsettingGlAccountId, "organizationPartyId", organizationPartyId)); + if (glAccountOrganization == null) { + return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have offsetting General Ledger account ["+offsettingGlAccountId+"] defined in GlAccountOrganization."); + } } - // Get the CRMSFA role for the initial responsible party String initialResponsibleRoleTypeId = PartyHelper.getFirstValidTeamMemberRoleTypeId(initialResponsiblePartyId, delegator); if (initialResponsibleRoleTypeId == null) { @@ -492,7 +496,7 @@ } } - if ((customer.get("outstandingBalance") != null) && (customer.getDouble("outstandingBalance").doubleValue() > 0.0)) { + if ((! UtilValidate.isEmpty(arGlAccountId)) && (! UtilValidate.isEmpty(offsettingGlAccountId)) && (customer.get("outstandingBalance") != null) && (customer.getDouble("outstandingBalance").doubleValue() > 0.0)) { // create an AcctgTrans, DR arGlAccountId, CR offsettingGlAccountId for the amount of outstandingBalance Map input = UtilMisc.toMap("acctgTransTypeId", "INTERNAL_ACCTG_TRANS", "glFiscalTypeId", "ACTUAL", |
From: <cli...@gr...> - 2007-01-22 17:55:09
|
Author: cliberty Date: 2007-01-22 09:54:22 -0800 (Mon, 22 Jan 2007) New Revision: 49 Modified: versions/0.9/trunk/entitydef/entitymodel_customer.xml versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java Log: Shortening the column name for DataImportCustomer.shipToStateProvinceGeoName to shipToStateProvGeoName Modified: versions/0.9/trunk/entitydef/entitymodel_customer.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_customer.xml 2007-01-22 14:40:14 UTC (rev 48) +++ versions/0.9/trunk/entitydef/entitymodel_customer.xml 2007-01-22 17:54:22 UTC (rev 49) @@ -93,7 +93,7 @@ <description>Must match OFBiz Geo.geoId</description> </field> <field name="shipToPostalCode" type="short-varchar"/> - <field name="shipToStateProvinceGeoName" type="id"/> + <field name="shipToStateProvGeoName" type="id"/> <field name="shipToCountryGeoId" type="id"> <description>Must match OFBiz Geo.geoId</description> </field> Modified: versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java 2007-01-22 14:40:14 UTC (rev 48) +++ versions/0.9/trunk/src/org/opentaps/dataimport/CustomerImportServices.java 2007-01-22 17:54:22 UTC (rev 49) @@ -150,11 +150,11 @@ // make sure the supplied GL accounts exist for the organization GenericValue glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", arGlAccountId, "organizationPartyId", organizationPartyId)); if (glAccountOrganization == null) { - return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have Accounts Receivable General Ledger account ["+arGlAccountId+"] defined in GlAccountOrganization."); +// return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have Accounts Receivable General Ledger account ["+arGlAccountId+"] defined in GlAccountOrganization."); } glAccountOrganization = delegator.findByPrimaryKey("GlAccountOrganization", UtilMisc.toMap("glAccountId", offsettingGlAccountId, "organizationPartyId", organizationPartyId)); if (glAccountOrganization == null) { - return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have offsetting General Ledger account ["+offsettingGlAccountId+"] defined in GlAccountOrganization."); +// return ServiceUtil.returnError("Cannot import customers: organization ["+organizationPartyId+"] does not have offsetting General Ledger account ["+offsettingGlAccountId+"] defined in GlAccountOrganization."); } @@ -298,7 +298,7 @@ if (!UtilValidate.isEmpty(customer.getString("shipToAddress1"))) { // associate this as SHIPPING_LOCATION GenericValue contactMech = delegator.makeValue("ContactMech", UtilMisc.toMap("contactMechId", delegator.getNextSeqId("ContactMech"), "contactMechTypeId", "POSTAL_ADDRESS")); - GenericValue secondaryPostalAddress = makePostalAddress(contactMech, customer.getString("shipToCompanyName"), customer.getString("shipToFirstName"), customer.getString("shipToLastName"), customer.getString("shipToAttnName"), customer.getString("shipToAddress1"), customer.getString("shipToAddress2"), customer.getString("shipToCity"), customer.getString("shipToStateProvinceGeoId"), customer.getString("shipToPostalCode"), customer.getString("shipToStateProvinceGeoName"), customer.getString("shipToCountryGeoId"), delegator); + GenericValue secondaryPostalAddress = makePostalAddress(contactMech, customer.getString("shipToCompanyName"), customer.getString("shipToFirstName"), customer.getString("shipToLastName"), customer.getString("shipToAttnName"), customer.getString("shipToAddress1"), customer.getString("shipToAddress2"), customer.getString("shipToCity"), customer.getString("shipToStateProvinceGeoId"), customer.getString("shipToPostalCode"), customer.getString("shipToStateProvGeoName"), customer.getString("shipToCountryGeoId"), delegator); toStore.add(contactMech); toStore.add(secondaryPostalAddress); if (personPartyId != null) { |
From: <cli...@gr...> - 2007-01-22 14:40:21
|
Author: cliberty Date: 2007-01-22 06:40:14 -0800 (Mon, 22 Jan 2007) New Revision: 48 Added: versions/0.9/trunk/entitydef/entitymodel_order.xml versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql versions/0.9/trunk/script/mysql/importOrderItemsExample.sql versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java Modified: versions/0.9/trunk/entitydef/entitygroup.xml versions/0.9/trunk/ofbiz-component.xml versions/0.9/trunk/servicedef/services.xml Log: Adding order import entities and services Modified: versions/0.9/trunk/entitydef/entitygroup.xml =================================================================== --- versions/0.9/trunk/entitydef/entitygroup.xml 2007-01-18 21:18:57 UTC (rev 47) +++ versions/0.9/trunk/entitydef/entitygroup.xml 2007-01-22 14:40:14 UTC (rev 48) @@ -31,4 +31,11 @@ <entity-group group="org.ofbiz" entity="DataImportProduct"/> + <!-- =================================== --> + <!-- org.opentaps.dataimport.orders --> + <!-- =================================== --> + + <entity-group group="org.ofbiz" entity="DataImportOrderHeader"/> + <entity-group group="org.ofbiz" entity="DataImportOrderItem"/> + </entitygroup> Added: versions/0.9/trunk/entitydef/entitymodel_order.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-01-18 21:18:57 UTC (rev 47) +++ versions/0.9/trunk/entitydef/entitymodel_order.xml 2007-01-22 14:40:14 UTC (rev 48) @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Honest Public License. + * + * This program 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 + * Honest Public License for more details. + * + * You should have received a copy of the Honest Public License + * along with this program; if not, write to Funambol, + * 643 Bair Island Road, Suite 305 - Redwood City, CA 94063, USA +--> + +<entitymodel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/entitymodel.xsd"> + <!-- ========================================================= --> + <!-- ======================== Defaults ======================= --> + <!-- ========================================================= --> + <title>Order Data Import Entities</title> + <description>Defines intermediate entities for importing order data</description> + <copyright>Copyright (c) 2006 - 2007 Open Source Strategies, Inc.</copyright> + <author>Chris Liberty (cli...@op...)</author> + <version>1.0</version> + + <!-- ================================= --> + <!-- org.opentaps.dataimport.orders --> + <!-- ================================= --> + + <!-- for precise definitions of the field types see the file framework/entity/fieldtype/fieldtypeXXX.xml for your database XXX --> + + <entity entity-name="DataImportOrderHeader" + package-name="org.opentaps.dataimport.orders" + title="Intermediate import entity for order header data."> + <field name="orderId" type="id-ne"></field> + <field name="orderTypeId" type="id"></field> + <field name="customerPartyId" type="id"></field> + <field name="orderDate" type="date-time"></field> + <field name="currencyUomId" type="id"></field> + <field name="shippingTotal" type="currency-amount"></field> + <field name="taxTotal" type="currency-amount"></field> + <field name="adjustmentsTotal" type="currency-amount"></field> + <field name="grandTotal" type="currency-amount"></field> + <field name="comments" type="comment"></field> + <field name="processedTimestamp" type="date-time"> + <description>Special field for system to record when entry was successfully imported. + Do not use for any other purpose.</description> + </field> + <prim-key field="orderId"/> + <relation type="one" fk-name="IMPT_ORDERHDR_TYPE" rel-entity-name="OrderType"> + <key-map field-name="orderTypeId"/> + </relation> + <relation type="one" fk-name="IMPT_ORDERHDR_PTY" rel-entity-name="Party"> + <key-map field-name="customerPartyId" rel-field-name="partyId"/> + </relation> + <relation type="one" fk-name="IMPT_ORDERHDR_CUOM" rel-entity-name="Uom"> + <key-map field-name="currencyUomId" rel-field-name="uomId"/> + </relation> + </entity> + + <entity entity-name="DataImportOrderItem" + package-name="org.opentaps.dataimport.orders" + title="Intermediate import entity for order item data."> + <field name="orderId" type="id-ne"></field> + <field name="productId" type="id"></field> + <field name="quantity" type="floating-point"></field> + <field name="price" type="currency-amount"></field> + <field name="itemAdjustmentsTotal" type="currency-amount"></field> + <field name="customerPo" type="id"></field> + <field name="comments" type="comment"></field> + <field name="processedTimestamp" type="date-time"> + <description>Special field for system to record when entry was successfully imported. + Do not use for any other purpose.</description> + </field> + <field name="orderItemSeqId" type="id"> + <description>Special field for system to record the primary orderItemSeqId created against this order item record. + Do not use for any other purpose.</description> + </field> + <prim-key field="orderId"/> + <prim-key field="productId"/> + <prim-key field="quantity"/> + <prim-key field="price"/> + <prim-key field="itemAdjustmentsTotal"/> + <relation type="one" fk-name="IMPT_ORDERITEM_HDR" rel-entity-name="DataImportOrderHeader"> + <key-map field-name="orderId"/> + </relation> + <relation type="one" fk-name="IMPT_ORDERITEM_PRD" rel-entity-name="Product"> + <key-map field-name="productId"/> + </relation> + </entity> + + +</entitymodel> Modified: versions/0.9/trunk/ofbiz-component.xml =================================================================== --- versions/0.9/trunk/ofbiz-component.xml 2007-01-18 21:18:57 UTC (rev 47) +++ versions/0.9/trunk/ofbiz-component.xml 2007-01-22 14:40:14 UTC (rev 48) @@ -25,6 +25,7 @@ <!-- these entities are to help importing data and can be removed if not needed --> <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_customer.xml"/> + <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_order.xml"/> <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_product.xml"/> <entity-resource type="group" reader-name="main" loader="main" location="entitydef/entitygroup.xml"/> Added: versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql 2007-01-18 21:18:57 UTC (rev 47) +++ versions/0.9/trunk/script/mysql/importOrderHeadersExample.sql 2007-01-22 14:40:14 UTC (rev 48) @@ -0,0 +1,40 @@ +-- Example MySQL script for importing order headers +-- orderDate must be in SQL yyyy-mm-dd hh:mm::ss.fff timestamp format +-- customerId must exist as partyId in the Party entity +-- grandTotal, shippingTotal, taxTotal, adjustmentsTotal may be positive or negative numbers +-- currencyUomId must exist in the Uom entity +-- orderTypeId must exist in the OrderType entity + +load data local infile +'' +ignore +into table data_import_order_header +fields optionally enclosed by '"' +lines terminated by '\r' +ignore 1 lines + +( + @orderId, + @orderDate, + @customerId, + @grandTotal, + @shippingTotal, + @taxTotal, + @adjustmentsTotal, + @currencyUomId, + @comments, + @orderTypeId, +) + +set +order_id = nullif(trim(@orderId),''), +order_type_id = case trim(@orderTypeId) when 'DI' then 'SALES_ORDER' when 'CI' then 'PURCHASE_ORDER' else null end, +customer_party_id = nullif(trim(@customerId),''), +order_date = nullif(trim(@orderDate),''), +currency_uom_id = nullif(trim(ucase(@currencyUomId)),''), +shipping_total = nullif(trim(@shippingTotal),''), +tax_total = nullif(trim(@taxTotal),''), +adjustments_total = nullif(trim(@adjustmentsTotal),''), +grand_total = nullif(trim(@grandTotal),''), +comments = nullif(trim(@comments),''); + Added: versions/0.9/trunk/script/mysql/importOrderItemsExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importOrderItemsExample.sql 2007-01-18 21:18:57 UTC (rev 47) +++ versions/0.9/trunk/script/mysql/importOrderItemsExample.sql 2007-01-22 14:40:14 UTC (rev 48) @@ -0,0 +1,33 @@ +-- Example MySQL script for importing order items. +-- orderId must be present in data_import_order_header.orderId +-- productId must exist in the Product entity +-- quantity, price and adjustmentsTotal may be positive or negative numbers + +load data local infile +'' +ignore +into table data_import_order_item +fields optionally enclosed by '"' +lines terminated by '\r' +ignore 1 lines + +( + @itemOrderId, + @customerPo, + @productId, + @quantity, + @price, + @adjustmentsTotal, + @comments +) + +set +order_id = nullif(trim(@itemOrderId),''), +product_id = nullif(trim(@productId),''), +quantity = nullif(trim(ucase(@quantity)),''), +price = nullif(trim(@price),''), +adjustments_total = nullif(trim(@adjustmentsTotal),''), +customer_po = nullif(trim(@customerPo),''), +comments = nullif(trim(@comments),''); + + Modified: versions/0.9/trunk/servicedef/services.xml =================================================================== --- versions/0.9/trunk/servicedef/services.xml 2007-01-18 21:18:57 UTC (rev 47) +++ versions/0.9/trunk/servicedef/services.xml 2007-01-22 14:40:14 UTC (rev 48) @@ -51,4 +51,29 @@ <attribute type="Integer" mode="OUT" name="productsImported" optional="true"/> </service> + <service name="importOrders" engine="java" use-transaction="false" + location="org.opentaps.dataimport.OrderImportServices" invoke="importOrders"> + <description> + Import orders using DataImportOrderHeader and DataImportOrderItems. + Note that this service is not wrapped in a transaction. Each orderHeader/orderItems record set imported is in its + own transaction, so it can store as many good records as possible. + companyPartyId is the ID of the billFromVendor for the orders. + productStoreId is the productStore that the orders should be related to. + prodCatalogId is the productCatalog that the orders should be related to (optional). + importEmptyOrders controls whether orderHeaders + with no corresponding orderItems should be imported or ignored. + calculateGrandTotal controls whether the grand total for the order should be taken from the DataImportOrderHeader.grandTotal + field or calculated from orderItems and orderAdjustments + ignoreShippingHeaderAdjustment controls whether the DataImportOrderHeader.shippingTotal should be made + into an orderAdjustment or ignored. + </description> + <attribute type="String" mode="IN" name="companyPartyId" optional="false"/> + <attribute type="String" mode="IN" name="productStoreId" optional="false"/> + <attribute type="String" mode="IN" name="prodCatalogId" optional="true"/> + <attribute type="Boolean" mode="IN" name="importEmptyOrders" optional="false"/> + <attribute type="Boolean" mode="IN" name="calculateGrandTotal" optional="false"/> + <attribute type="Boolean" mode="IN" name="ignoreShippingHeaderAdjustment" optional="false"/> + <attribute type="Integer" mode="OUT" name="productsImported" optional="true"/> + </service> + </services> Added: versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-01-18 21:18:57 UTC (rev 47) +++ versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java 2007-01-22 14:40:14 UTC (rev 48) @@ -0,0 +1,336 @@ +package org.opentaps.dataimport; + +import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.ServiceUtil; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.util.EntityListIterator; +import org.ofbiz.entity.transaction.TransactionUtil; +import org.ofbiz.entity.condition.EntityConditionList; +import org.ofbiz.entity.condition.EntityExpr; +import org.ofbiz.entity.condition.EntityOperator; +import org.ofbiz.base.util.*; + +import java.util.Map; +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; +import java.sql.Timestamp; +import java.math.BigDecimal; + +import javolution.util.FastList; +import javolution.util.FastMap; + +/** + * Import orders via intermediate DataImportOrderHeader and DataImportOrderItem entities. + * + * @author <a href="mailto:cli...@op...">Chris Liberty</a> + * @version $Rev$ + */ +public class OrderImportServices { + + public static String module = OrderImportServices.class.getName(); + public static final int decimals = UtilNumber.getBigDecimalScale("order.decimals"); + public static final int rounding = UtilNumber.getBigDecimalRoundingMode("order.rounding"); + public static final BigDecimal ZERO = (new BigDecimal("0")).setScale(decimals, rounding); + + public static Map importOrders(DispatchContext dctx, Map context) { + GenericDelegator delegator = dctx.getDelegator(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String companyPartyId = (String) context.get("companyPartyId"); + String productStoreId = (String) context.get("productStoreId"); + String prodCatalogId = (String) context.get("prodCatalogId"); + Boolean importEmptyOrders = (Boolean) context.get("importEmptyOrders"); + Boolean calculateGrandTotal = (Boolean) context.get("calculateGrandTotal"); + Boolean ignoreShippingHeaderAdjustment = (Boolean) context.get("ignoreShippingHeaderAdjustment"); + + int imported = 0; + + // main try/catch block that traps errors related to obtaining data from delegator + try { + + // Make sure the productStore exists + GenericValue productStore = delegator.findByPrimaryKey("ProductStore", UtilMisc.toMap("productStoreId", productStoreId)); + + if (UtilValidate.isEmpty(productStore)) { + String errMsg = "Error in importOrders service: product store [" + productStoreId + "] does not exist"; + Debug.logError(errMsg, OrderImportServices.module); + return ServiceUtil.returnError(errMsg); + } + + // Make sure the productCatalog exists + if (! UtilValidate.isEmpty(prodCatalogId)) { + GenericValue productCatalog = delegator.findByPrimaryKey("ProdCatalog", UtilMisc.toMap("prodCatalogId", prodCatalogId)); + + if (UtilValidate.isEmpty(productCatalog)) { + String errMsg = "Error in importOrders service: product catalog [" + productCatalog + "] does not exist"; + Debug.logError(errMsg, OrderImportServices.module); + return ServiceUtil.returnError(errMsg); + } + } + + // Make sure the company party exists + GenericValue companyParty = delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", companyPartyId)); + + if (UtilValidate.isEmpty(companyParty)) { + String errMsg = "Error in importOrders service: company party [" + companyPartyId + "] does not exist"; + Debug.logError(errMsg, OrderImportServices.module); + return ServiceUtil.returnError(errMsg); + } + + // Ensure the party role for the company + List billFromRoles = companyParty.getRelatedByAnd("PartyRole", UtilMisc.toMap("roleTypeId", "BILL_FROM_VENDOR")); + if (billFromRoles.size() == 0) { + delegator.create("PartyRole", UtilMisc.toMap("partyId", companyPartyId, "roleTypeId", "BILL_FROM_VENDOR")); + } + + // need to get an ELI because of possibly large number of records. productId <> null will get all records + EntityConditionList conditions = new EntityConditionList( UtilMisc.toList( + new EntityExpr("orderId", EntityOperator.NOT_EQUAL, null), + new EntityExpr("processedTimestamp", EntityOperator.EQUALS, null) // leave out previously processed orders + ), EntityOperator.AND); + TransactionUtil.begin(); // since the service is not inside a transaction, this needs to be in its own transaction, or you'll get a harmless exception + EntityListIterator importOrderHeaders = delegator.findListIteratorByCondition("DataImportOrderHeader", conditions, null, null); + TransactionUtil.commit(); + + GenericValue orderHeader = null; + while ((orderHeader = (GenericValue) importOrderHeaders.next()) != null) { + + try { + + List toStore = OrderImportServices.decodeOrder(orderHeader, companyPartyId, productStoreId, prodCatalogId, importEmptyOrders.booleanValue(), calculateGrandTotal.booleanValue(), ignoreShippingHeaderAdjustment.booleanValue(), delegator); + if (toStore == null) { + Debug.logWarning("Import of orderHeader["+orderHeader.get("orderId")+"] was unsuccessful.", OrderImportServices.module); + } + + TransactionUtil.begin(); + + delegator.storeAll(toStore); + + Debug.logInfo("Successfully imported orderHeader ["+orderHeader.get("orderId")+"].", OrderImportServices.module); + imported++; + + TransactionUtil.commit(); + + } catch ( GenericEntityException e) { + TransactionUtil.rollback(); + Debug.logError(e, "Failed to import orderHeader["+orderHeader.get("orderId")+"]. Error stack follows.", OrderImportServices.module); + } catch (Exception e) { + TransactionUtil.rollback(); + Debug.logWarning("Import of orderHeader["+orderHeader.get("orderId")+"] was unsuccessful.", OrderImportServices.module); + } + } + importOrderHeaders.close(); + + } catch (GenericEntityException e) { + String errMsg = "Error in importOrders service: " + e.getMessage(); + Debug.logError(e, errMsg, OrderImportServices.module); + return ServiceUtil.returnError(errMsg); + } + + Map results = ServiceUtil.returnSuccess(); + results.put("productsImported", new Integer(imported)); + return results; + } + + /** + * Helper method to decode a DataImportOrderHeader/DataImportOrderItem into a List of GenericValues modeling that product in the OFBiz schema. + * If for some reason obtaining data via the delegator fails, this service throws that exception. + * Note that everything is done with the delegator for maximum efficiency. + */ + private static List decodeOrder(GenericValue externalOrderHeader, String companyPartyId, String productStoreId, String prodCatalogId, boolean importEmptyOrders, boolean calculateGrandTotal, boolean ignoreShippingHeaderAdjustment, GenericDelegator delegator) throws GenericEntityException, Exception { + List toStore = FastList.newInstance(); + + String orderId = externalOrderHeader.getString("orderId"); + String orderTypeId = externalOrderHeader.getString("orderTypeId"); + if (UtilValidate.isEmpty(orderTypeId)) { + orderTypeId = "SALES_ORDER"; + } + Timestamp orderDate = externalOrderHeader.getTimestamp("orderDate"); + if (UtilValidate.isEmpty(orderDate)) { + orderDate = UtilDateTime.nowTimestamp(); + } + + Debug.logInfo("Importing orderHeader[" + orderId + "]", OrderImportServices.module); + + // Check to make sure that an order with this ID doesn't already exist + GenericValue existingOrderHeader = delegator.findByPrimaryKey("OrderHeader", UtilMisc.toMap("orderId", orderId)); + if (existingOrderHeader != null) { + Debug.logError("Ignoring duplicate orderHeader[" + orderId + "]", OrderImportServices.module); + return toStore; + } + + // OrderHeader + + Map orderHeaderInput = FastMap.newInstance(); + orderHeaderInput.put("orderId", orderId); + orderHeaderInput.put("orderTypeId", orderTypeId); + orderHeaderInput.put("orderName", orderId); + orderHeaderInput.put("externalId", orderId); + orderHeaderInput.put("salesChannelEnumId", "UNKNWN_SALES_CHANNEL"); + orderHeaderInput.put("orderDate", orderDate); + orderHeaderInput.put("entryDate", UtilDateTime.nowTimestamp()); + orderHeaderInput.put("statusId", "ORDER_COMPLETED"); + orderHeaderInput.put("currencyUom", externalOrderHeader.get("currencyUomId")); + orderHeaderInput.put("productStoreId", productStoreId); + orderHeaderInput.put("remainingSubTotal", new Double(0)); + + List orderAdjustments = new ArrayList(); + + // todo:Make orderAdjustments from adjustmentsTotal and taxTotal + + if (! ignoreShippingHeaderAdjustment) { + // todo:Make orderAdjustments from shippingTotal + } + + // OrderItems + + List orderItemConditions = UtilMisc.toList(new EntityExpr("orderId", EntityOperator.EQUALS, orderId), new EntityExpr("processedTimestamp", EntityOperator.EQUALS, null)); + List externalOrderItems = delegator.findByCondition("DataImportOrderItem", new EntityConditionList(orderItemConditions, EntityOperator.AND) ,null, null);//getExternalOrderItems(externalOrderHeader.getString("orderId"), delegator); + + // If orders without orderItems should not be imported, return now without doing anything + if (UtilValidate.isEmpty(externalOrderItems) && ! importEmptyOrders) { + return toStore; + } + + List orderItems = new ArrayList(); + for (int count = 0 ; count < externalOrderItems.size() ; count++) { + GenericValue externalOrderItem = (GenericValue) externalOrderItems.get(count); + + String orderItemSeqId = UtilFormatOut.formatPaddedNumber(count + 1, 5); + + Map orderItemInput = FastMap.newInstance(); + orderItemInput.put("orderId", orderId ); + orderItemInput.put("orderItemSeqId", orderItemSeqId); + orderItemInput.put("orderItemTypeId", "PRODUCT_ORDER_ITEM" ); + if (! UtilValidate.isEmpty(externalOrderItem.get("productId"))) { + orderItemInput.put("productId", externalOrderItem.getString("productId")); + orderItemInput.put("itemDescription", externalOrderItem.getRelatedOneCache("Product").getString("description")); + } + if (! UtilValidate.isEmpty(prodCatalogId)) { + orderItemInput.put("prodCatalogId", prodCatalogId ); + } + orderItemInput.put("isPromo", "N" ); + if (! UtilValidate.isEmpty(externalOrderItem.get("quantity"))) { + orderItemInput.put("quantity", externalOrderItem.getDouble("quantity")); + } else { + orderItemInput.put("quantity", new Double(0)); + } + orderItemInput.put("selectedAmount", new Double(0) ); + if (! UtilValidate.isEmpty(externalOrderItem.get("price"))) { + orderItemInput.put("unitPrice", externalOrderItem.getDouble("price")); + orderItemInput.put("unitListPrice", externalOrderItem.getDouble("price")); + } else { + orderItemInput.put("unitPrice", new Double(0)); + orderItemInput.put("unitListPrice", new Double(0)); + } + orderItemInput.put("isModifiedPrice", "N" ); + if (! UtilValidate.isEmpty(externalOrderItem.get("comments"))) { + orderItemInput.put("comments", externalOrderItem.getString("comments")); + } + if (! UtilValidate.isEmpty(externalOrderItem.get("customerPo"))) { + orderItemInput.put("correspondingPoId", externalOrderItem.getString("customerPo")); + } + orderItemInput.put("statusId", "ITEM_COMPLETED" ); + orderItems.add(delegator.makeValue("OrderItem", orderItemInput)); + + // todo:Make orderAdjustment from itemAdjustmentsTotal and add to orderAdjustments list + + externalOrderItem.set("processedTimestamp", UtilDateTime.nowTimestamp()); + externalOrderItem.set("orderItemSeqId", orderItemSeqId); + } + + BigDecimal orderGrandTotal; + if (calculateGrandTotal) { + + // Get the grand total from the order items and order adjustments + orderGrandTotal = getOrderGrandTotal(orderAdjustments, orderItems); + } else { + orderGrandTotal = externalOrderHeader.getBigDecimal("grandTotal").setScale(decimals, rounding); + } + + orderHeaderInput.put("grandTotal", new Double(orderGrandTotal.doubleValue())); + toStore.add(delegator.makeValue("OrderHeader", orderHeaderInput)); + + toStore.addAll(orderItems); + toStore.addAll(externalOrderItems); + + // OrderRoles + + String customerPartyId = externalOrderHeader.getString("customerPartyId"); + if (! UtilValidate.isEmpty(customerPartyId)) { + + // Make sure the customer party exists + GenericValue party = delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", customerPartyId)); + + if (UtilValidate.isEmpty(party)) { + Debug.logError("CustomerPartyId [" + customerPartyId + "] not found - not creating BILL_TO_CUSTOMER order role for orderId [" + orderId + "]", module); + } else { + + // Ensure the party roles for the customer + List placingRoles = party.getRelatedByAnd("PartyRole", UtilMisc.toMap("roleTypeId", "PLACING_CUSTOMER")); + if (placingRoles.size() == 0) { + toStore.add(delegator.makeValue("PartyRole", UtilMisc.toMap("partyId", customerPartyId, "roleTypeId", "PLACING_CUSTOMER"))); + } + List billToRoles = party.getRelatedByAnd("PartyRole", UtilMisc.toMap("roleTypeId", "BILL_TO_CUSTOMER")); + if (billToRoles.size() == 0) { + toStore.add(delegator.makeValue("PartyRole", UtilMisc.toMap("partyId", customerPartyId, "roleTypeId", "BILL_TO_CUSTOMER"))); + } + List shipToRoles = party.getRelatedByAnd("PartyRole", UtilMisc.toMap("roleTypeId", "SHIP_TO_CUSTOMER")); + if (shipToRoles.size() == 0) { + toStore.add(delegator.makeValue("PartyRole", UtilMisc.toMap("partyId", customerPartyId, "roleTypeId", "SHIP_TO_CUSTOMER"))); + } + List endUserRoles = party.getRelatedByAnd("PartyRole", UtilMisc.toMap("roleTypeId", "END_USER_CUSTOMER")); + if (endUserRoles.size() == 0) { + toStore.add(delegator.makeValue("PartyRole", UtilMisc.toMap("partyId", customerPartyId, "roleTypeId", "END_USER_CUSTOMER"))); + } + + // Create the customer order roles + toStore.add(delegator.makeValue("OrderRole", UtilMisc.toMap("orderId", orderId, "partyId", customerPartyId, "roleTypeId", "PLACING_CUSTOMER"))); + toStore.add(delegator.makeValue("OrderRole", UtilMisc.toMap("orderId", orderId, "partyId", customerPartyId, "roleTypeId", "BILL_TO_CUSTOMER"))); + toStore.add(delegator.makeValue("OrderRole", UtilMisc.toMap("orderId", orderId, "partyId", customerPartyId, "roleTypeId", "SHIP_TO_CUSTOMER"))); + toStore.add(delegator.makeValue("OrderRole", UtilMisc.toMap("orderId", orderId, "partyId", customerPartyId, "roleTypeId", "END_USER_CUSTOMER"))); + } + } + + // Create the company order role + toStore.add(delegator.makeValue("OrderRole", UtilMisc.toMap("orderId", orderId, "partyId", companyPartyId, "roleTypeId", "BILL_FROM_VENDOR"))); + + // Order Note + String comments = externalOrderHeader.getString("comments"); + if (! UtilValidate.isEmpty(comments)) { + String noteId = delegator.getNextSeqId("NoteData"); + toStore.add(delegator.makeValue("NoteData", UtilMisc.toMap("noteId", noteId, "noteInfo", comments))); + toStore.add(delegator.makeValue("OrderHeaderNote", UtilMisc.toMap("orderId", orderId, "noteId", noteId, "internalNote", "Y"))); + } + + // Set the processedTimestamp on the externalOrderHeader + externalOrderHeader.set("processedTimestamp", UtilDateTime.nowTimestamp()); + toStore.add(externalOrderHeader); + + return toStore; + } + + private static BigDecimal getOrderGrandTotal(List orderAdjustments, List orderItems) { + BigDecimal grandTotal = ZERO; + + Iterator oajit = orderAdjustments.iterator(); + while (oajit.hasNext()) { + GenericValue orderAdjustment = (GenericValue) oajit.next(); + grandTotal = grandTotal.add(orderAdjustment.getBigDecimal("amount").setScale(decimals, rounding)); + } + Iterator oiit = orderItems.iterator(); + while (oiit.hasNext()) { + GenericValue orderItem = (GenericValue) oiit.next(); + BigDecimal quantity = orderItem.getBigDecimal("quantity").setScale(decimals, rounding); + BigDecimal price = orderItem.getBigDecimal("unitPrice").setScale(decimals, rounding); + + // Order item adjustments are included in orderAdjustments above - no need to consider them here + BigDecimal orderItemSubTotal = quantity.multiply(price); + grandTotal = grandTotal.add(orderItemSubTotal); + } + return grandTotal; + } +} Property changes on: versions/0.9/trunk/src/org/opentaps/dataimport/OrderImportServices.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + "Date Rev Author URL Id" |
From: <cli...@gr...> - 2007-01-18 21:19:01
|
Author: cliberty Date: 2007-01-18 13:18:57 -0800 (Thu, 18 Jan 2007) New Revision: 47 Added: versions/0.9/trunk/script/mysql/importProductCategoryMembersExample.sql Log: Adding MySQL script to create ProductCategoryMember records for each product Added: versions/0.9/trunk/script/mysql/importProductCategoryMembersExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importProductCategoryMembersExample.sql 2007-01-12 22:22:58 UTC (rev 46) +++ versions/0.9/trunk/script/mysql/importProductCategoryMembersExample.sql 2007-01-18 21:18:57 UTC (rev 47) @@ -0,0 +1,20 @@ +-- Creates product_category_member records for each existing product to @productCategoryId + +set @productCategoryId = 'PARTS'; + +insert into product_category_member(product_category_id, product_id, from_date, thru_date, comments, sequence_num, quantity, last_updated_stamp, last_updated_tx_stamp, created_stamp, created_tx_stamp) +select + @productCategoryId, + product_id, + '2007-1-17 4:12:12.0', + null, + null, + null, + null, + '2007-1-17 4:12:12.0', + '2007-1-17 4:12:12.0', + '2007-1-17 4:12:12.0', + '2007-1-17 4:12:12.0' +from product + + |
From: <cli...@gr...> - 2007-01-12 22:23:01
|
Author: cliberty Date: 2007-01-12 14:22:58 -0800 (Fri, 12 Jan 2007) New Revision: 46 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Log: Fix for productFeature and productFeatureAppl in importProducts service Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-11 20:14:31 UTC (rev 45) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-12 22:22:58 UTC (rev 46) @@ -175,17 +175,16 @@ input = FastMap.newInstance(); input.put("productFeatureId", productFeatureId); input.put("description", data.get("productFeature1")); + input.put("productFeatureTypeId", "OTHER_FEATURE"); productFeature = delegator.makeValue("ProductFeature", input); toStore.add(productFeature); - - input = FastMap.newInstance(); - input.put("productId", product.get("productId")); - input.put("productFeatureId", productFeatureId); - input.put("productFeatureTypeId", "OTHER_FEATURE"); - input.put("fromDate", now); - GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl", input); - toStore.add(productFeatureAppl); } + input = FastMap.newInstance(); + input.put("productId", product.get("productId")); + input.put("productFeatureId", productFeatureId); + input.put("fromDate", now); + GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl", input); + toStore.add(productFeatureAppl); } // update the original data record with a timestamp which also denotes that it has been processed (processedTimestamp = null was original search condition) |
From: Si C. <si...@gr...> - 2007-01-11 20:14:45
|
Author: sichen Date: 2007-01-11 12:14:31 -0800 (Thu, 11 Jan 2007) New Revision: 45 Modified: versions/0.9/trunk/script/mysql/importBOMExample.sql Log: comments on import bom Modified: versions/0.9/trunk/script/mysql/importBOMExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importBOMExample.sql 2007-01-11 17:38:26 UTC (rev 44) +++ versions/0.9/trunk/script/mysql/importBOMExample.sql 2007-01-11 20:14:31 UTC (rev 45) @@ -1,3 +1,6 @@ +--This is a simple example of importing a Bill of Materials. The products must have already been imported with product imports +--and the BOM file basically has productId, productIdTo, and quantity. I + load data local infile '' ignore |
From: Leon T. <le...@gr...> - 2007-01-11 17:38:31
|
Author: leon Date: 2007-01-11 09:38:26 -0800 (Thu, 11 Jan 2007) New Revision: 44 Added: versions/0.9/trunk/entitydef/entitymodel_product.xml versions/0.9/trunk/script/mysql/findRecursiveBoms.bsh Log: Added missing entitymodel file, added new script to find recursive BOM trees Added: versions/0.9/trunk/entitydef/entitymodel_product.xml =================================================================== --- versions/0.9/trunk/entitydef/entitymodel_product.xml 2007-01-10 22:27:02 UTC (rev 43) +++ versions/0.9/trunk/entitydef/entitymodel_product.xml 2007-01-11 17:38:26 UTC (rev 44) @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Honest Public License. + * + * This program 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 + * Honest Public License for more details. + * + * You should have received a copy of the Honest Public License + * along with this program; if not, write to Funambol, + * 643 Bair Island Road, Suite 305 - Redwood City, CA 94063, USA +--> + +<entitymodel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/entitymodel.xsd"> + <!-- ========================================================= --> + <!-- ======================== Defaults ======================= --> + <!-- ========================================================= --> + <title>Product Data Import Entities</title> + <description>Defines intermediate entities for importing customer data</description> + <copyright>Copyright (c) 2006 - 2007 Open Source Strategies, Inc.</copyright> + <author>Leon Torres (le...@op...)</author> + <version>1.0</version> + + <!-- ================================= --> + <!-- org.opentaps.dataimport.customers --> + <!-- ================================= --> + + <!-- for precise definitions of the field types see the file framework/entity/fieldtype/fieldtypeXXX.xml for your database XXX --> + + <entity entity-name="DataImportProduct" + package-name="org.opentaps.dataimport.products" + title="Intermediate import entity for product data."> + <field name="productId" type="id-ne"/> + <field name="productTypeId" type="id-ne"/> + <field name="customId1" type="id"/> + <field name="customId2" type="id"/> + <field name="description" type="description"/> + <field name="weight" type="floating-point"/> + <field name="weightUomId" type="id"/> + <field name="productLength" type="floating-point"/> + <field name="productLengthUomId" type="id"/> + <field name="width" type="floating-point"/> + <field name="widthUomId" type="id"/> + <field name="height" type="floating-point"/> + <field name="heightUomId" type="id"/> + <field name="price" type="currency-precise"/> + <field name="priceCurrencyUomId" type="id"/> + <field name="productFeature1" type="description"/> + <field name="processedTimestamp" type="date-time"> + <description>Special field for system to record when entry was successfully imported. + Do not use for any other purpose.</description> + </field> + <prim-key field="productId"/> + </entity> + +</entitymodel> Added: versions/0.9/trunk/script/mysql/findRecursiveBoms.bsh =================================================================== --- versions/0.9/trunk/script/mysql/findRecursiveBoms.bsh 2007-01-10 22:27:02 UTC (rev 43) +++ versions/0.9/trunk/script/mysql/findRecursiveBoms.bsh 2007-01-11 17:38:26 UTC (rev 44) @@ -0,0 +1,127 @@ +/** + * This script will find self-referential BOM tress. + */ +import java.util.*; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.service.GenericDispatcher; +import org.ofbiz.base.util.*; +import org.ofbiz.entity.util.*; +delegator = GenericDelegator.getGenericDelegator("default"); +dispatcher = GenericDispatcher.getLocalDispatcher("ecommerce", delegator); +admin = delegator.findByPrimaryKey("UserLogin", UtilMisc.toMap("userLoginId", "admin")); + +// hard limit of recursions to print, set to -1 to find all +limit = -1; + +// store all recursion productIds +recursions = new HashSet(); + +boms = delegator.findByAnd("ProductAssoc", UtilMisc.toMap("productAssocTypeId", "MANUF_COMPONENT")); + +fromSet = new HashSet(); +toSet = new HashSet(); +for (iter = boms.iterator(); iter.hasNext(); ) { + bom = iter.next(); + + // detect self-referential entries + if (bom.get("productId").equals(bom.get("productIdTo"))) { + print("Self-referential entry detected: productId ["+bom.get("productId")+"], productIdTo ["+bom.get("productIdTo")+"]"); + recursions.add(bom.get("productId")); + iter.remove(); + continue; + } + + fromSet.add(bom.get("productId")); + toSet.add(bom.get("productIdTo")); +} + +// find entries that aren't referenced in productIdTo +rootBoms = new HashSet(); +for (iter = fromSet.iterator(); iter.hasNext(); ) { + from = iter.next(); + if (!toSet.contains(from)) + rootBoms.add(from); +} +rootSize = rootBoms.size(); +print("Root products detected: " + rootSize); + +// find all terminator products +termBoms = new HashSet(); +for (iter = toSet.iterator(); iter.hasNext(); ) { + to = iter.next(); + if (!fromSet.contains(to)) + termBoms.add(to); +} +termSize = termBoms.size(); +print("Terminator products detected: " + termSize); + +// remove all root and terminator entries to speed things up +for (iter = boms.iterator(); iter.hasNext(); ) { + bom = iter.next(); + if (rootBoms.contains(bom.get("productId"))) + iter.remove(); + else if (termBoms.contains(bom.get("productIdTo"))) + iter.remove(); +} + +// if a recursion is encountered, returns true +boolean walkTree(String parentId, Set allChildren, int level, String rootId) { + hasRecursions = false; + directChildren = new HashSet(); + + line = ""; + if (rootId != null) { + indent = ""; + for (int i = 0; i < level; i++) indent += "-"; + line = indent + (level == 0 ? "" : "> ") + parentId; + } + + for (iter = boms.iterator(); iter.hasNext(); ) { + bom = iter.next(); + if (parentId.equals(bom.get("productId"))) { + childId = bom.get("productIdTo"); + if (recursions.contains(childId)) { + hasRecursions = true; + if (rootId != null && rootId.equals(childId)) line += "\n" + indent + "-> " + childId + " RECURSION"; + continue; + } else if (allChildren.contains(childId)) { // TODO: this doesn't necessarily identify a recursion, it could identify a common terminus + recursions.add(childId); + hasRecursions = true; + if (rootId != null && rootId.equals(childId)) line += "\n" + indent + "-> " + childId + " RECURSION"; + continue; + } + directChildren.add(childId); + } + } + + if (rootId != null) print(line); + + // walk the non-recursive children + allChildren.addAll(directChildren); + for (iter = directChildren.iterator(); iter.hasNext(); ) { + if (walkTree(iter.next(), allChildren, level + 1, rootId)) + hasRecursions = true; + } + return hasRecursions; +} + +// for each remaining node, traverse its children and look for a self-reference +for (iter = boms.iterator(); iter.hasNext(); ) { + bom = iter.next(); + productId = bom.get("productId"); + if (recursions.contains(productId)) continue; + set = new HashSet(); + set.add(productId); + if (!walkTree(productId, set, 0, null)) { + iter.remove(); // remove the non-recursive trees to speed things up + } + if (limit != -1 && recursions.size() >= limit) break; +} + +// print the recursion trees found (note that those that have no children are not actually recursions, they're terminations) +for (iter = recursions.iterator(); iter.hasNext(); ) { + id = iter.next(); + set = new HashSet(); + set.add(id); + walkTree(id, set, 0, id); +} |
From: Leon T. <le...@gr...> - 2007-01-10 22:27:07
|
Author: leon Date: 2007-01-10 14:27:02 -0800 (Wed, 10 Jan 2007) New Revision: 43 Modified: versions/0.9/trunk/script/mysql/importBOMExample.sql Log: Delete trivial self-referential entries Modified: versions/0.9/trunk/script/mysql/importBOMExample.sql =================================================================== --- versions/0.9/trunk/script/mysql/importBOMExample.sql 2007-01-10 00:55:34 UTC (rev 42) +++ versions/0.9/trunk/script/mysql/importBOMExample.sql 2007-01-10 22:27:02 UTC (rev 43) @@ -18,3 +18,6 @@ PRODUCT_ASSOC_TYPE_ID = 'MANUF_COMPONENT', FROM_DATE = '2007-01-01 00:00:00.0', QUANTITY = @quantity +; + +delete from PRODUCT_ASSOC where PRODUCT_ID = PRODUCT_ID_TO and PRODUCT_ASSOC_TYPE_ID = 'MANUF_COMPONENT' and FROM_DATE = '2007-01-01 00:00:00.0'; |
From: Leon T. <le...@gr...> - 2007-01-10 00:55:35
|
Author: leon Date: 2007-01-09 16:55:34 -0800 (Tue, 09 Jan 2007) New Revision: 42 Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Log: Added default productFeatureTypeId = OTHER_FEATURE for imported features. Modified: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-10 00:41:43 UTC (rev 41) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-10 00:55:34 UTC (rev 42) @@ -166,7 +166,7 @@ toStore.add(goodIdentification); } - // product features (this is per productFeatureN) + // product features (this is per productFeatureN) all of these have type OTHER_FEATURE if (!UtilValidate.isEmpty(data.getString("productFeature1"))) { String productFeatureId = data.getString("productFeature1"); productFeatureId = productFeatureId.toUpperCase().replaceAll("\\s", "_"); @@ -181,6 +181,7 @@ input = FastMap.newInstance(); input.put("productId", product.get("productId")); input.put("productFeatureId", productFeatureId); + input.put("productFeatureTypeId", "OTHER_FEATURE"); input.put("fromDate", now); GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl", input); toStore.add(productFeatureAppl); |
From: Leon T. <le...@gr...> - 2007-01-10 00:41:45
|
Author: leon Date: 2007-01-09 16:41:43 -0800 (Tue, 09 Jan 2007) New Revision: 41 Added: versions/0.9/trunk/entitydef/entitygroup.xml versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Removed: versions/0.9/trunk/entitydef/entitygroup_customer.xml Modified: versions/0.9/trunk/ofbiz-component.xml versions/0.9/trunk/servicedef/services.xml Log: Service and intermediate entity for importing products. Also merge the entitygroup.xml files into one. Copied: versions/0.9/trunk/entitydef/entitygroup.xml (from rev 35, versions/0.9/trunk/entitydef/entitygroup_customer.xml) =================================================================== --- versions/0.9/trunk/entitydef/entitygroup_customer.xml 2007-01-09 18:28:47 UTC (rev 35) +++ versions/0.9/trunk/entitydef/entitygroup.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Honest Public License. + * + * This program 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 + * Honest Public License for more details. + * + * You should have received a copy of the Honest Public License + * along with this program; if not, write to Funambol, + * Foundation, Inc., 51 Frankli +n St, Fifth Floor, Boston, MA 02110-1301 USA +--> + +<entitygroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/entitygroup.xsd"> + + <!-- =================================== --> + <!-- org.opentaps.dataimport.customers --> + <!-- =================================== --> + + <entity-group group="org.ofbiz" entity="DataImportCustomer"/> + + <!-- =================================== --> + <!-- org.opentaps.dataimport.products --> + <!-- =================================== --> + + <entity-group group="org.ofbiz" entity="DataImportProduct"/> + +</entitygroup> Deleted: versions/0.9/trunk/entitydef/entitygroup_customer.xml =================================================================== --- versions/0.9/trunk/entitydef/entitygroup_customer.xml 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/entitydef/entitygroup_customer.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the Honest Public License. - * - * This program 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 - * Honest Public License for more details. - * - * You should have received a copy of the Honest Public License - * along with this program; if not, write to Funambol, - * Foundation, Inc., 51 Frankli -n St, Fifth Floor, Boston, MA 02110-1301 USA ---> - -<!-- TODO: merge into entitygroup.xml --> -<entitygroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/entitygroup.xsd"> - - <!-- =================================== --> - <!-- org.opentaps.dataimport.customers --> - <!-- =================================== --> - - <entity-group group="org.ofbiz" entity="DataImportCustomer"/> - -</entitygroup> Modified: versions/0.9/trunk/ofbiz-component.xml =================================================================== --- versions/0.9/trunk/ofbiz-component.xml 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/ofbiz-component.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -25,7 +25,8 @@ <!-- these entities are to help importing data and can be removed if not needed --> <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_customer.xml"/> - <entity-resource type="group" reader-name="main" loader="main" location="entitydef/entitygroup_customer.xml"/> + <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_product.xml"/> + <entity-resource type="group" reader-name="main" loader="main" location="entitydef/entitygroup.xml"/> <entity-resource type="data" reader-name="demo" loader="main" location="data/DemoImportCustomers.xml"/> Modified: versions/0.9/trunk/servicedef/services.xml =================================================================== --- versions/0.9/trunk/servicedef/services.xml 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/servicedef/services.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -38,4 +38,17 @@ <attribute type="Integer" mode="OUT" name="customersImported" optional="true"/> </service> + <service name="importProducts" engine="java" use-transaction="false" + location="org.opentaps.dataimport.ProductImportServices" invoke="importProducts"> + <description> + Import products using DataImportProduct. + Note that this service is not wrapped in a transaction. Each customer record imported is in its + own transaction, so it can store as many good records as possible. + The goodIdentificationTypeIdN parameters correspond to the type of the customIdN fields in DataImportProduct. + </description> + <attribute type="String" mode="IN" name="goodIdentificationTypeId1" optional="false"/> + <attribute type="String" mode="IN" name="goodIdentificationTypeId2" optional="false"/> + <attribute type="Integer" mode="OUT" name="productsImported" optional="true"/> + </service> + </services> Added: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-10 00:41:43 UTC (rev 41) @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Honest Public License. + * + * This program 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 + * Honest Public License for more details. + * + * You should have received a copy of the Honest Public License + * along with this program; if not, write to Funambol, + * 643 Bair Island Road, Suite 305 - Redwood City, CA 94063, USA + */ + +package org.opentaps.dataimport; + +import java.util.*; +import java.sql.Timestamp; +import java.math.BigDecimal; + +import javolution.util.FastList; +import javolution.util.FastMap; + +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.base.util.*; +import org.ofbiz.entity.*; +import org.ofbiz.entity.condition.*; +import org.ofbiz.entity.util.*; +import org.ofbiz.entity.transaction.TransactionUtil; +import org.ofbiz.service.ServiceUtil; +import org.ofbiz.service.DispatchContext; + +/** + * Import products via intermediate DataImportProduct entity. + * + * @author <a href="mailto:le...@op...">Leon Torres</a> + */ +public class ProductImportServices { + + public static String module = ProductImportServices.class.getName(); + + public static Map importProducts(DispatchContext dctx, Map context) { + GenericDelegator delegator = dctx.getDelegator(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String goodIdentificationTypeId1 = (String) context.get("goodIdentificationTypeId1"); + String goodIdentificationTypeId2 = (String) context.get("goodIdentificationTypeId2"); + Timestamp now = UtilDateTime.nowTimestamp(); + + int imported = 0; + + // main try/catch block that traps errors related to obtaining data from delegator + try { + // need to get an ELI because of possibly large number of records. productId <> null will get all records + EntityConditionList conditions = new EntityConditionList( UtilMisc.toList( + new EntityExpr("productId", EntityOperator.NOT_EQUAL, null), + new EntityExpr("processedTimestamp", EntityOperator.EQUALS, null) // leave out previously processed products + ), EntityOperator.AND); + TransactionUtil.begin(); // since the service is not inside a transaction, this needs to be in its own transaction, or you'll get a harmless exception + EntityListIterator importProducts = delegator.findListIteratorByCondition("DataImportProduct", conditions, null, null); + TransactionUtil.commit(); + + GenericValue product = null; + while ((product = (GenericValue) importProducts.next()) != null) { + + try { + // use the helper method to decode the product into a List of GenericValues + List toStore = decodeProduct(product, now, goodIdentificationTypeId1, goodIdentificationTypeId2, delegator); + if (toStore == null) { + Debug.logWarning("Faild to import product["+product.get("productId")+"] because data was bad. Check preceding warnings for reason.", module); + } + + // next we're going to store all each product's data in its own transaction, so if one product's data is bad, the others will still get stored + TransactionUtil.begin(); + + // store the results and mark this product as processed + delegator.storeAll(toStore); + + // log the import + Debug.logInfo("Successfully imported product ["+product.get("productId")+"].", module); + imported += 1; + + TransactionUtil.commit(); + + } catch (GenericEntityException e) { + // if there was an error, we'll just skip this product + TransactionUtil.rollback(); + Debug.logError(e, "Faild to import product["+product.get("productId")+"]. Error stack follows.", module); + } catch (Exception e) { + TransactionUtil.rollback(); + Debug.logError(e, "Faild to import product["+product.get("productId")+"]. Error stack follows.", module); + } + } + importProducts.close(); + + } catch (GenericEntityException e) { + String message = "Cannot import products: Unable to use delegator to retrieve data from the database. Error is: " + e.getMessage(); + Debug.logError(e, message, module); + return ServiceUtil.returnError(message); + } + + Map results = ServiceUtil.returnSuccess(); + results.put("productsImported", new Integer(imported)); + return results; + } + + /** + * Helper method to decode a DataImportProduct into a List of GenericValues modeling that product in the OFBiz schema. + * If for some reason obtaining data via the delegator fails, this service throws that exception. + * Note that everything is done with the delegator for maximum efficiency. + */ + private static List decodeProduct(GenericValue data, Timestamp now, String goodIdentificationTypeId1, String goodIdentificationTypeId2, GenericDelegator delegator) throws GenericEntityException, Exception { + Map input; + List toStore = FastList.newInstance(); + Debug.logInfo("Now processing data [" + data.get("productId") + "] description [" + data.get("description") + "]", module); + + // product + input = FastMap.newInstance(); + input.put("productId", data.get("productId")); + input.put("productTypeId", data.get("productTypeId")); + input.put("internalName", data.get("description")); + input.put("description", data.get("description")); + input.put("productName", data.get("description")); + input.put("productHeight", data.get("height")); + input.put("heightUomId", data.get("heightUomId")); + input.put("productDepth", data.get("productLength")); + input.put("depthUomId", data.get("productLengthUomId")); + input.put("productWidth", data.get("width")); + input.put("widthUomId", data.get("widthUomId")); + input.put("weight", data.get("weight")); + input.put("weightUomId", data.get("weightUomId")); + input.put("createdDate", now); + GenericValue product = delegator.makeValue("Product", input); + toStore.add(product); + + // product price + input = FastMap.newInstance(); + input.put("productId", product.get("productId")); + input.put("productPriceTypeId", "DEFAULT_PRICE"); + input.put("productPricePurposeId", "PURCHASE"); + input.put("productStoreGroupId", "_NA_"); + input.put("currencyUomId", data.get("priceCurrencyUomId")); + input.put("fromDate", now); + input.put("price", data.get("price")); + input.put("createdDate", now); + GenericValue productPrice = delegator.makeValue("ProductPrice", input); + toStore.add(productPrice); + + // good identification (this is per customIdN) + if (!UtilValidate.isEmpty(data.getString("customId1"))) { + input = FastMap.newInstance(); + input.put("goodIdentificationTypeId", goodIdentificationTypeId1); + input.put("productId", product.get("productId")); + input.put("idValue", data.get("customId1")); + GenericValue goodIdentification = delegator.makeValue("GoodIdentification", input); + toStore.add(goodIdentification); + } + if (!UtilValidate.isEmpty(data.getString("customId2"))) { + input = FastMap.newInstance(); + input.put("goodIdentificationTypeId", goodIdentificationTypeId2); + input.put("productId", product.get("productId")); + input.put("idValue", data.get("customId2")); + GenericValue goodIdentification = delegator.makeValue("GoodIdentification", input); + toStore.add(goodIdentification); + } + + // product features (this is per productFeatureN) + if (!UtilValidate.isEmpty(data.getString("productFeature1"))) { + String productFeatureId = data.getString("productFeature1"); + productFeatureId = productFeatureId.toUpperCase().replaceAll("\\s", "_"); + GenericValue productFeature = delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", productFeatureId)); + if (productFeature == null) { + input = FastMap.newInstance(); + input.put("productFeatureId", productFeatureId); + input.put("description", data.get("productFeature1")); + productFeature = delegator.makeValue("ProductFeature", input); + toStore.add(productFeature); + + input = FastMap.newInstance(); + input.put("productId", product.get("productId")); + input.put("productFeatureId", productFeatureId); + input.put("fromDate", now); + GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl", input); + toStore.add(productFeatureAppl); + } + } + + // update the original data record with a timestamp which also denotes that it has been processed (processedTimestamp = null was original search condition) + data.set("processedTimestamp", UtilDateTime.nowTimestamp()); + toStore.add(data); + + return toStore; + } +} |