private function commitProducts($orderId, $rawInput, $itemAddressMap, $editingExisting=false, $adjustInventory=true) { $orderId = (int)$orderId; if (!$orderId) { $this->setError("Invalid arguments passed to commitProducts"); return false; } /** @var ISC_QUOTE */ $quote = $rawInput['quote']; $existingOrder = false; $existingProducts = false; if ($editingExisting && $orderId) { $existingOrder = $this->get($orderId); if (!$existingOrder) { $this->setError("editingExisting specified in commitProducts but order " . $orderId . " not found"); return false; } // prune products from the existing order which are no longer on the incoming edit (products tied to unused addresses should already be gone after commitAddresses()) $this->deleteUnusedOrderProducts($orderId, $quote); $existingProducts = $this->getOrderProducts($orderId); $existingProducts = Interspire_Array::remapToSubkey($existingProducts, 'orderprodid'); // make existing products easier to find by id } $giftCertificates = array(); foreach($quote->getItems() as /** @var ISC_QUOTE_ITEM */$item) { $itemType = 'physical'; if($item->getType() == PT_DIGITAL) { $itemType = 'digital'; } else if($item instanceof ISC_QUOTE_ITEM_GIFTCERTIFICATE) { // Gift certificates cannot be modified so continue if this is an existing order if($existingOrder) { continue; } $itemType = 'giftcertificate'; $giftCertificates[] = $item; } $existingProduct = false; if (is_numeric($item->getId())) { // numeric quote_item id denotes existing order_product, but if it doesn't exist for some reason treat it as a new order_product I guess if (isset($existingProducts[$item->getId()])) { $existingProduct = $existingProducts[$item->getId()]; } } // addresses are already stored in db and assigned real ids by commitAddresses() $addressId = 0; $itemAddressId = $item->getAddressId(); if(isset($itemAddressMap[$itemAddressId])) { $addressId = $itemAddressMap[$itemAddressId]; } $appliedDiscounts = $item->getDiscounts(); if (empty($appliedDiscounts)) { $appliedDiscounts = ''; } else { $appliedDiscounts = serialize($appliedDiscounts); } // build order_products data for upsert $newProduct = array( 'orderorderid' => $orderId, 'ordprodid' => $item->getProductId(), 'ordprodsku' => $item->getSku(), 'ordprodname' => $item->getName(), 'ordprodtype' => $itemType, 'ordprodqty' => $item->getQuantity(), 'base_price' => $item->getBasePrice(), 'price_ex_tax' => $item->getPrice(false), 'price_inc_tax' => $item->getPrice(true), 'price_tax' => $item->getTax(), 'base_total' => $item->getBaseTotal(), 'total_ex_tax' => $item->getTotal(false), 'total_inc_tax' => $item->getTotal(true), 'total_tax' => $item->getTaxTotal(), 'base_cost_price' => $item->getBaseCostPrice(), 'cost_price_inc_tax' => $item->getCostPrice(false), 'cost_price_inc_tax' => $item->getCostPrice(true), 'cost_price_tax' => $item->getCostPriceTax(), 'ordprodweight' => $item->getWeight(), 'ordprodoptions' => '', 'ordprodvariationid' => $item->getVariationid(), 'ordprodwrapid' => 0, 'ordprodwrapname' => '', 'base_wrapping_cost' => $item->getBaseWrappingCost(), 'wrapping_cost_ex_tax' => $item->getWrappingCost(false), 'wrapping_cost_inc_tax' => $item->getWrappingCost(true), 'wrapping_cost_tax' => $item->getWrappingCost(true) - $item->getWrappingCost(false), 'ordprodwrapmessage' => '', 'ordprodeventname' => $item->getEventName(), 'ordprodeventdate' => $item->getEventDate(true), 'ordprodfixedshippingcost' => $item->getFixedShippingCost(), 'order_address_id' => $addressId, 'applied_discounts' => $appliedDiscounts, ); $variationOptions = $item->getVariationOptions(); if(!empty($variationOptions)) { $newProduct['ordprodoptions'] = serialize($variationOptions); } $wrapping = $item->getGiftWrapping(); if(!empty($wrapping)) { $newProduct['ordprodwrapid'] = $wrapping['wrapid']; $newProduct['ordprodwrapname'] = $wrapping['wrapname']; $newProduct['ordprodwrapmessage'] = $wrapping['wrapmessage']; } // upsert to order_products if ($existingProduct) { if (!$this->db->UpdateQuery('order_products', $newProduct, "orderprodid = " . $existingProduct['orderprodid'])) { $this->setError("Failed to update existing order product"); return false; } // remove existing configurable fields so they can be reinserted if needed $this->deleteOrderProductConfigurableFields($existingProduct['orderprodid']); } else { $orderProductId = $GLOBALS['ISC_CLASS_DB']->insertQuery('order_products', $newProduct); if(!$orderProductId) { $this->setError("Failed to insert new order product"); return false; } } // adjust inventory levels for existing orders only (UpdateOrderStatus() seems to do it for new orders) if ($adjustInventory && $existingOrder && $existingOrder['ordinventoryupdated']) { $inventoryRequiresAdjustment = true; if ($existingProduct && $existingProduct['ordprodid']) { if ($existingProduct['ordprodid'] == $item->getProductId() && $existingProduct['ordprodvariationid'] == $item->getVariationId() && $existingProduct['ordprodqty'] == $item->getQuantity()) { // don't bother adjusting if the product, variation and qty details have not changed $inventoryRequiresAdjustment = false; } if ($inventoryRequiresAdjustment) { $product = $this->product->get($existingProduct['ordprodid']); if ($product) { // put old product inventory back to store if (!AdjustProductInventory($existingProduct['ordprodid'], $existingProduct['ordprodvariationid'], $product['prodinvtrack'], '+' . $existingProduct['ordprodqty'])) { $this->setError("Failed to adjust inventory for old order product"); return false; } } } } // pull new product inventory from store if ($inventoryRequiresAdjustment && $item->getProductId()) { if (!AdjustProductInventory($item->getProductId(), $item->getVariationId(), $item->getInventoryTrackingMethod(), '-' . $item->getQuantity())) { $this->setError("Failed to adjust inventory for new order product"); return false; } } } $configurableFields = $item->getConfiguration(); foreach($configurableFields as $fieldId => $field) { if($field['type'] == 'file' && trim($field['value']) != '') { $filePath = ISC_BASE_PATH.'/'.GetConfig('ImageDirectory').'/configured_products/'.$field['value']; $fileTmpPath = ISC_BASE_PATH.'/'.GetConfig('ImageDirectory').'/configured_products_tmp/'.$field['value']; //do not remove the temp file here, because the payment may not successful //the file should still be viewable in in the cart, @copy($fileTmpPath, $filePath); } $newField = array( 'ordprodid' => $orderProductId, 'fieldid' => $fieldId, 'orderid' => $orderId, 'fieldname' => $field['name'], 'fieldtype' => $field['type'], 'fieldselectoptions' => '', 'textcontents' => '', 'filename' => '', 'filetype' => '', 'originalfilename' => '', 'productid' => $item->getProductId(), ); if($field['type'] == 'file' && trim($field['value']) != '') { $newField['filename'] = trim($field['value']); $newField['filetype'] = trim($field['fileType']); $newField['originalfilename'] = trim($field['fileOriginalName']); } elseif ($field['type'] == 'select') { $newField['fieldselectoptions'] = $field['selectOptions']; $newField['textcontents'] = trim($field['value']); } else { $newField['textcontents'] = trim($field['value']); } if(!$GLOBALS['ISC_CLASS_DB']->InsertQuery('order_configurable_fields', $newField)) { return false; } } } if(!empty($giftCertificates)) { getClass('ISC_GIFTCERTIFICATES')->createGiftCertificatesFromOrder( $orderId, $giftCertificates, 1 ); } return true; }